Beispiel #1
0
/* Resolve a bound function on value stack top to a non-bound target
 * (leave other values as is).
 */
DUK_INTERNAL void duk_resolve_nonbound_function(duk_context *ctx) {
	duk_tval *tv;

	tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
	if (DUK_TVAL_IS_OBJECT(tv)) {
		duk_hobject *h;

		h = DUK_TVAL_GET_OBJECT(tv);
		DUK_ASSERT(h != NULL);
		if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) {
			duk_push_tval(ctx, &((duk_hboundfunc *) h)->target);
			duk_replace(ctx, -2);
#if 0
			DUK_TVAL_SET_TVAL(tv, &((duk_hboundfunc *) h)->target);
			DUK_TVAL_INCREF(thr, tv);
			DUK_HOBJECT_DECREF_NORZ(thr, h);
#endif
			/* Rely on Function.prototype.bind() on never creating a bound
			 * function whose target is not proper.  This is now safe
			 * because the target is not even an internal property but a
			 * struct member.
			 */
			DUK_ASSERT(duk_is_lightfunc(ctx, -1) || duk_is_callable(ctx, -1));
		}
	}

	/* Lightfuncs cannot be bound but are always callable and
	 * constructable.
	 */
}
DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx, void *udata) {
	duk_hthread *thr;

	DUK_ASSERT(ctx != NULL);
	thr = (duk_hthread *) ctx;
	DUK_UNREF(udata);

	DUK_DDD(DUK_DDDPRINT("protected finalization helper running"));

	/* [... obj] */

	/* XXX: Finalizer lookup should traverse the prototype chain (to allow
	 * inherited finalizers) but should not invoke accessors or proxy object
	 * behavior.  At the moment this lookup will invoke proxy behavior, so
	 * caller must ensure that this function is not called if the target is
	 * a Proxy.
	 */

	duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_FINALIZER);  /* -> [... obj finalizer] */
	if (!duk_is_callable(ctx, -1)) {
		DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable"));
		return 0;
	}
	duk_dup_m2(ctx);
	duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
	DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer"));
	duk_call(ctx, 2);  /* [ ... obj finalizer obj heapDestruct ]  -> [ ... obj retval ] */
	DUK_DDD(DUK_DDDPRINT("finalizer finished successfully"));
	return 0;

	/* Note: we rely on duk_safe_call() to fix up the stack for the caller,
	 * so we don't need to pop stuff here.  There is no return value;
	 * caller determines rescued status based on object refcount.
	 */
}
Beispiel #3
0
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
	(void) duk_push_this_coercible_to_object(ctx);
	duk_get_prop_stridx(ctx, -1, DUK_STRIDX_JOIN);

	/* [ ... this func ] */
	if (!duk_is_callable(ctx, -1)) {
		/* Fall back to the initial (original) Object.toString().  We don't
		 * currently have pointers to the built-in functions, only the top
		 * level global objects (like "Array") so this is now done in a bit
		 * of a hacky manner.  It would be cleaner to push the (original)
		 * function and use duk_call_method().
		 */

		/* XXX: 'this' will be ToObject() coerced twice, which is incorrect
		 * but should have no visible side effects.
		 */
		DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString"));
		duk_set_top(ctx, 0);
		return duk_bi_object_prototype_to_string(ctx);  /* has access to 'this' binding */
	}

	/* [ ... this func ] */

	duk_insert(ctx, -2);

	/* [ ... func this ] */

	DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT",
	                     (duk_tval *) duk_get_tval(ctx, -2),
	                     (duk_tval *) duk_get_tval(ctx, -1)));
	duk_call_method(ctx, 0);

	return 1;
}
static int UIButton_Popup(duk_context* ctx)
{

    if (!duk_is_object(ctx, 0))
    {
        duk_push_string(ctx, "UIButton.popup first argument must be an object");
        duk_throw(ctx);
    }
    if (!duk_is_callable(ctx, 1))
    {
        duk_push_string(ctx, "UIButton.popup second argument must be callable");
        duk_throw(ctx);
    }

    JSVM* vm = JSVM::GetJSVM(ctx);

    duk_enum(ctx, 0, DUK_ENUM_OWN_PROPERTIES_ONLY);

    UISelectItemSource* source = new UISelectItemSource(vm->GetContext());

    while (duk_next(ctx, -1, 0)) {

        String key = duk_get_string(ctx, -1);

        duk_get_prop(ctx, 0);

        if (duk_is_array(ctx, -1))
        {
            // need to support this, for skin image, etc
            assert(0);
        }
        else if (duk_is_string(ctx, -1))
        {
            // id
            String id = duk_get_string(ctx, -1);            
            source->AddItem(new UISelectItem(vm->GetContext(), key, id));
        }
        else
        {
            duk_push_string(ctx, "UIButton.popup data object key is not an array or string");
            duk_throw(ctx);
        }

        duk_pop(ctx);  // pop key value
    }

    duk_pop(ctx);  // pop enum object

    duk_push_this(ctx);

    duk_dup(ctx, 1);
    duk_put_prop_string(ctx, -2, "__popup_menu_callback");

    UIButton* button = js_to_class_instance<UIButton>(ctx, -1, 0);
    UIMenuWindow* menuWindow = new UIMenuWindow(vm->GetContext(), button, "__popup-menu");
    menuWindow->Show(source);
    duk_pop(ctx);

    return 0;
}
DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) {
	duk_idx_t len;
	duk_idx_t i;

	DUK_ASSERT_TOP(ctx, 2);  /* not a vararg function */

	duk_push_this(ctx);
	if (!duk_is_callable(ctx, -1)) {
		DUK_DDD(DUK_DDDPRINT("func is not callable"));
		goto type_error;
	}
	duk_insert(ctx, 0);
	DUK_ASSERT_TOP(ctx, 3);

	DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT",
	                     (duk_tval *) duk_get_tval(ctx, 0),
	                     (duk_tval *) duk_get_tval(ctx, 1),
	                     (duk_tval *) duk_get_tval(ctx, 2)));

	/* [ func thisArg argArray ] */

	if (duk_is_null_or_undefined(ctx, 2)) {
		DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args"));
		len = 0;
	} else if (!duk_is_object(ctx, 2)) {
		goto type_error;
	} else {
		DUK_DDD(DUK_DDDPRINT("argArray is an object"));

		/* XXX: make this an internal helper */
		duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH);
		len = (duk_idx_t) duk_to_uint32(ctx, -1);  /* ToUint32() coercion required */
		duk_pop(ctx);

		duk_require_stack(ctx, len);

		DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len));
		for (i = 0; i < len; i++) {
			duk_get_prop_index(ctx, 2, i);
		}
	}
	duk_remove(ctx, 2);
	DUK_ASSERT_TOP(ctx, 2 + len);

	/* [ func thisArg arg1 ... argN ] */

	DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld",
	                     (duk_tval *) duk_get_tval(ctx, 0),
	                     (duk_tval *) duk_get_tval(ctx, 1),
	                     (long) len));
	duk_call_method(ctx, len);
	return 1;

 type_error:
	return DUK_RET_TYPE_ERROR;
}
Beispiel #6
0
DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx) {
	DUK_ASSERT_TOP(ctx, 0);
	(void) duk_push_this_coercible_to_object(ctx);
	duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_STRING);
	if (!duk_is_callable(ctx, 1)) {
		return DUK_RET_TYPE_ERROR;
	}
	duk_dup(ctx, 0);  /* -> [ O toString O ] */
	duk_call_method(ctx, 0);  /* XXX: call method tailcall? */
	return 1;
}
/*
 * If there is a callback registered for this interface pushes the function onto the stack
 */
static int PushServiceCallback(duk_context* ctx, const char* iface)
{
    AJS_GetGlobalStashObject(ctx, "serviceCB");

    duk_get_prop_string(ctx, -1, iface);
    duk_remove(ctx, -2);
    if (duk_is_callable(ctx, -1)) {
        return 1;
    } else {
        duk_pop(ctx);
        return 0;
    }
}
AJ_Status AJS_HandleAcceptSession(duk_context* ctx, AJ_Message* msg, uint16_t port, uint32_t sessionId, const char* joiner)
{
    uint32_t accept = TRUE;
    SessionInfo* sessionInfo;

    /*
     * Create an entry in the sessions table so we can track this peer
     */
    AJS_GetGlobalStashObject(ctx, "sessions");
    sessionInfo = AllocSessionObject(ctx, joiner);
    /*
     * If there is no handler automatically accept the connection
     */
    AJS_GetAllJoynProperty(ctx, "onPeerConnected");
    if (duk_is_callable(ctx, -1)) {
        /* Empty interface array */
        duk_push_array(ctx);
        AddServiceObject(ctx, sessionInfo, "/", joiner);
        if (AJS_DebuggerIsAttached()) {
            msg = AJS_CloneAndCloseMessage(ctx, msg);
        }
        if (duk_pcall(ctx, 1) != DUK_EXEC_SUCCESS) {
            AJS_ConsoleSignalError(ctx);
            accept = FALSE;
        } else {
            accept = duk_get_boolean(ctx, -1);
        }
    }
    duk_pop_2(ctx);
    /*
     * It is possible that we already have an outbound session to this peer so if we are not
     * accepting the session we can only delete the entry if the refCount is zero.
     */
    if (accept) {
        ++sessionInfo->refCount;
        sessionInfo->port = port;
        sessionInfo->sessionId = sessionId;
    } else if (sessionInfo->refCount == 0) {
        duk_del_prop_string(ctx, -1, joiner);
    }
    /* Pop sessions object */
    duk_pop(ctx);
    return AJ_BusReplyAcceptSession(msg, accept);
}
Beispiel #9
0
AJ_Status AJS_ServiceIO(duk_context* ctx)
{
    AJS_IO_PinTriggerCondition condition;
    int32_t trigId;

    trigId = AJS_TargetIO_PinTrigId(&condition);
    if (trigId != AJS_IO_PIN_NO_TRIGGER) {
        AJ_InfoPrintf(("triggered on id %d\n", trigId));
        /*
         * Lookup the pin object in the triggers array
         */
        duk_get_global_string(ctx, AJS_IOObjectName);
        duk_get_prop_string(ctx, -1, AJS_HIDDEN_PROP("trigs"));
        do {
            duk_get_prop_index(ctx, -1, trigId);
            if (duk_is_object(ctx, -1)) {
                /*
                 * Call the trigger function passing the pin object and value as the argument
                 */
                duk_get_prop_string(ctx, -1, "trigger");
                if (duk_is_callable(ctx, -1)) {
                    /*
                     * Pin object is the "this" object
                     */
                    duk_dup(ctx, -2);
                    duk_push_int(ctx, condition);
                    if (duk_pcall_method(ctx, 1) != DUK_EXEC_SUCCESS) {
                        AJS_ConsoleSignalError(ctx);
                    }
                }
                /*
                 * Pop pin object
                 */
                duk_pop(ctx);
            } else {
                AJ_ErrPrintf(("Expected a pin object trigId = %d\n", trigId));
            }
            duk_pop(ctx);
            trigId = AJS_TargetIO_PinTrigId(&condition);
        } while (trigId != AJS_IO_PIN_NO_TRIGGER);
        duk_pop_2(ctx);
    }
    return AJ_OK;
}
Beispiel #10
0
static int duk_disasm(RAsm *a, RAsmOp *op, const ut8 *buf, int len) {
	int res = 0, res2 = 0;
	const char *opstr = NULL;
	ut8 *b = a->cur->user;
	duk_push_global_stash (ctx);
	duk_dup (ctx, 0);  /* timer callback */
	duk_get_prop_string (ctx, -2, "disfun");
	b = a->cur->user = duk_require_tval (ctx, -1);
//	pushBuffer (buf, len);
	if (duk_is_callable(ctx, -1)) {
		int i;
		// duk_push_string (ctx, "TODO 2");
		pushBuffer (buf, len);
		duk_call (ctx, 1);

		// [ size, str ]
		for (i = 0; i<3; i++) {
			duk_dup_top (ctx);
			duk_get_prop_index (ctx, -1, i);
			if (duk_is_number (ctx, -1)) {
				if (res)
				res2 = duk_to_number (ctx, -1);
				else
				res2 = res = duk_to_number (ctx, -1);
			} else if (duk_is_string (ctx, -1)) {
				if (!opstr) {
					opstr = duk_to_string (ctx, -1);
				}
			}
			duk_pop (ctx);
		}
	} else {
		eprintf ("[:(] Is not a function %02x %02x\n", b[0],b[1]);
	}

	// fill op struct
	op->size = res;
	if (!opstr) opstr = "invalid";
	strncpy (op->buf_asm, opstr, sizeof (op->buf_asm));
	r_hex_bin2str (buf, op->size, op->buf_hex);
	return res2;
}
/*
 * Delete session info object pointed to by sessionId. If sessionId
 * is zero then delete all session info objects.
 */
static AJ_Status RemoveSessions(duk_context* ctx, uint32_t sessionId)
{
    AJ_Status status = AJ_OK;
    AJS_GetGlobalStashObject(ctx, "sessions");
    duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY);
    while (duk_next(ctx, -1, 1)) {
        SessionInfo* sessionInfo;
        const char* peer = duk_get_string(ctx, -2);
        duk_get_prop_string(ctx, -1, "info");
        sessionInfo = duk_get_buffer(ctx, -1, NULL);
        duk_pop_3(ctx);
        if (sessionId == 0) {
            AJ_InfoPrintf(("RemoveSessions(): Leaving session: %u\n", sessionInfo->sessionId));
            status = AJ_BusLeaveSession(AJS_GetBusAttachment(), sessionInfo->sessionId);
        } else if (sessionInfo->sessionId == sessionId) {
            status = AJ_BusLeaveSession(AJS_GetBusAttachment(), sessionInfo->sessionId);
            duk_del_prop_string(ctx, -2, peer);
            break;
        }
    }
    duk_pop_2(ctx);
    /*
     * TODO - this is not all that useful because it only indicates that a peer has gone away
     * without being able to specify exactly which services are affected. The problem is we cannot
     * hold a reference to the service object because we a relying on the service object finalizer
     * to clean up sessions that are no longer in use. If we hold a reference the finalizer will
     * never get called.
     */
    if (sessionId != 0) {
        AJS_GetAllJoynProperty(ctx, "onPeerDisconnected");
        if (duk_is_callable(ctx, -1)) {
            if (duk_pcall(ctx, 0) != DUK_EXEC_SUCCESS) {
                AJS_ConsoleSignalError(ctx);
            }
        }
        duk_pop(ctx);
    } else {
        AJS_ClearGlobalStashObject(ctx, "sessions");
    }
    return status;
}
Beispiel #12
0
duk_ret_t duk_bi_thread_constructor(duk_context *ctx) {
	duk_hthread *new_thr;
	duk_hobject *func;

	if (!duk_is_callable(ctx, 0)) {
		return DUK_RET_TYPE_ERROR;
	}
	func = duk_get_hobject(ctx, 0);
	DUK_ASSERT(func != NULL);

	duk_push_thread(ctx);
	new_thr = (duk_hthread *) duk_get_hobject(ctx, -1);
	DUK_ASSERT(new_thr != NULL);
	new_thr->state = DUK_HTHREAD_STATE_INACTIVE;

	/* push initial function call to new thread stack; this is
	 * picked up by resume().
	 */
	duk_push_hobject((duk_context *) new_thr, func);

	return 1;  /* return thread */
}
static int _finalize_helper(duk_context *ctx) {
	DUK_ASSERT(ctx != NULL);

	DUK_DDDPRINT("protected finalization helper running");

	/* [... obj] */

	duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_FINALIZER);  /* -> [... obj finalizer] */
	if (!duk_is_callable(ctx, -1)) {
		DUK_DDDPRINT("-> no finalizer or finalizer not callable");
		return 0;
	}
	duk_dup(ctx, -2);  /* -> [... obj finalizer obj] */
	DUK_DDDPRINT("-> finalizer found, calling finalizer");
	duk_call(ctx, 1);  /* -> [... obj retval] */
	DUK_DDDPRINT("finalizer finished successfully");
	return 0;

	/* Note: we rely on duk_safe_call() to fix up the stack for the caller,
	 * so we don't need to pop stuff here.  There is no return value;
	 * caller determines rescued status based on object refcount.
	 */
}
Beispiel #14
0
static int duk_assemble(RAsm *a, RAsmOp *op, const char *str) {
	int i, res = 0;
	// call myasm function if available
	duk_push_global_stash (ctx);
	duk_dup (ctx, 0);  /* timer callback */
	duk_get_prop_string (ctx, -2, "asmfun");
	a->cur->user = duk_require_tval (ctx, -1);
	if (duk_is_callable(ctx, -1)) {
		duk_push_string (ctx, str);
		duk_call (ctx, 1);
		// [ array of bytes ]
		//duk_dup_top (ctx);
		res = duk_get_length (ctx, -1);
		op->size = res;
		for (i=0; i<res; i++) {
			duk_dup_top (ctx);
			duk_get_prop_index (ctx, -2, i);
			op->buf[i] = duk_to_int (ctx, -1);
		}
	}
	if (res<1)
		res = -1;
	return res;
}
//duk_bool_t duk_is_callable(duk_context *ctx, duk_idx_t index);
duk_bool_t aperl_duk_is_callable(duk_context *ctx, duk_idx_t index) {
	duk_bool_t ret = duk_is_callable(ctx, index);
	return ret;
}
static duk_ret_t test_func(duk_context *ctx, void *udata) {
	(void) udata;

	if (ctx) {
		printf("dummy - return here\n"); fflush(stdout);
		return 0;
	}

	/* Up-to-date for Duktape 1.3.0, alphabetical order:
	 * $ cd website/api; ls *.yaml
	 */

	(void) duk_alloc_raw(ctx, 0);
	(void) duk_alloc(ctx, 0);
	(void) duk_base64_decode(ctx, 0);
	(void) duk_base64_encode(ctx, 0);
	(void) duk_buffer_to_string(ctx, 0);
	(void) duk_call_method(ctx, 0);
	(void) duk_call_prop(ctx, 0, 0);
	(void) duk_call(ctx, 0);
	(void) duk_char_code_at(ctx, 0, 0);
	(void) duk_check_stack_top(ctx, 0);
	(void) duk_check_stack(ctx, 0);
	(void) duk_check_type_mask(ctx, 0, 0);
	(void) duk_check_type(ctx, 0, 0);
	(void) duk_compact(ctx, 0);
	(void) duk_compile_lstring_filename(ctx, 0, "dummy", 0);
	(void) duk_compile_lstring(ctx, 0, "dummy", 0);
	(void) duk_compile_string_filename(ctx, 0, "dummy");
	(void) duk_compile_string(ctx, 0, "dummy");
	(void) duk_compile(ctx, 0);
	(void) duk_concat(ctx, 0);
	(void) duk_config_buffer(ctx, 0, NULL, 0);
	(void) duk_copy(ctx, 0, 0);
	(void) duk_create_heap_default();
	(void) duk_create_heap(NULL, NULL, NULL, NULL, NULL);
	(void) duk_debugger_attach(ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
	(void) duk_debugger_cooperate(ctx);
	(void) duk_debugger_detach(ctx);
	(void) duk_debugger_notify(ctx, 0);
	(void) duk_debugger_pause(ctx);
	(void) duk_decode_string(ctx, 0, NULL, NULL);
	(void) duk_def_prop(ctx, 0, 0);
	(void) duk_del_prop_index(ctx, 0, 0);
	(void) duk_del_prop_string(ctx, 0, "dummy");
	(void) duk_del_prop(ctx, 0);
	(void) duk_destroy_heap(ctx);
	(void) duk_dump_function(ctx);
	(void) duk_dup_top(ctx);
	(void) duk_dup(ctx, 0);
	(void) duk_enum(ctx, 0, 0);
	(void) duk_equals(ctx, 0, 0);
	duk_error_va(ctx, 0, NULL, NULL);
	duk_error(ctx, 0, "dummy");  /* (void) cast won't work without variadic macros */
	(void) duk_eval_lstring_noresult(ctx, "dummy", 0);
	(void) duk_eval_lstring(ctx, "dummy", 0);
	(void) duk_eval_noresult(ctx);
	(void) duk_eval_string_noresult(ctx, "dummy");
	(void) duk_eval_string(ctx, "dummy");
	(void) duk_eval(ctx);
	(void) duk_fatal(ctx, "dummy");
	(void) duk_free_raw(ctx, NULL);
	(void) duk_free(ctx, NULL);
	(void) duk_gc(ctx, 0);
	(void) duk_get_boolean(ctx, 0);
	(void) duk_get_buffer_data(ctx, 0, NULL);
	(void) duk_get_buffer(ctx, 0, NULL);
	(void) duk_get_c_function(ctx, 0);
	(void) duk_get_context(ctx, 0);
	(void) duk_get_current_magic(ctx);
	(void) duk_get_error_code(ctx, 0);
	(void) duk_get_finalizer(ctx, 0);
	(void) duk_get_global_string(ctx, 0);
	(void) duk_get_heapptr(ctx, 0);
	(void) duk_get_int(ctx, 0);
	(void) duk_get_length(ctx, 0);
	(void) duk_get_lstring(ctx, 0, NULL);
	(void) duk_get_magic(ctx, 0);
	(void) duk_get_memory_functions(ctx, NULL);
	(void) duk_get_number(ctx, 0);
	(void) duk_get_pointer(ctx, 0);
	(void) duk_get_prop_index(ctx, 0, 0);
	(void) duk_get_prop_string(ctx, 0, "dummy");
	(void) duk_get_prop(ctx, 0);
	(void) duk_get_prototype(ctx, 0);
	(void) duk_get_string(ctx, 0);
	(void) duk_get_top_index(ctx);
	(void) duk_get_top(ctx);
	(void) duk_get_type_mask(ctx, 0);
	(void) duk_get_type(ctx, 0);
	(void) duk_get_uint(ctx, 0);
	(void) duk_has_prop_index(ctx, 0, 0);
	(void) duk_has_prop_string(ctx, 0, "dummy");
	(void) duk_has_prop(ctx, 0);
	(void) duk_hex_decode(ctx, 0);
	(void) duk_hex_encode(ctx, 0);
	(void) duk_insert(ctx, 0);
	(void) duk_instanceof(ctx, 0, 0);
	(void) duk_is_array(ctx, 0);
	(void) duk_is_boolean(ctx, 0);
	(void) duk_is_bound_function(ctx, 0);
	(void) duk_is_buffer(ctx, 0);
	(void) duk_is_callable(ctx, 0);
	(void) duk_is_c_function(ctx, 0);
	(void) duk_is_constructor_call(ctx);
	(void) duk_is_dynamic_buffer(ctx, 0);
	(void) duk_is_ecmascript_function(ctx, 0);
	(void) duk_is_error(ctx, 0);
	(void) duk_is_eval_error(ctx, 0);
	(void) duk_is_fixed_buffer(ctx, 0);
	(void) duk_is_function(ctx, 0);
	(void) duk_is_lightfunc(ctx, 0);
	(void) duk_is_nan(ctx, 0);
	(void) duk_is_null_or_undefined(ctx, 0);
	(void) duk_is_null(ctx, 0);
	(void) duk_is_number(ctx, 0);
	(void) duk_is_object_coercible(ctx, 0);
	(void) duk_is_object(ctx, 0);
	(void) duk_is_pointer(ctx, 0);
	(void) duk_is_primitive(ctx, 0);
	(void) duk_is_range_error(ctx, 0);
	(void) duk_is_reference_error(ctx, 0);
	(void) duk_is_strict_call(ctx);
	(void) duk_is_string(ctx, 0);
	(void) duk_is_syntax_error(ctx, 0);
	(void) duk_is_thread(ctx, 0);
	(void) duk_is_type_error(ctx, 0);
	(void) duk_is_undefined(ctx, 0);
	(void) duk_is_uri_error(ctx, 0);
	(void) duk_is_valid_index(ctx, 0);
	(void) duk_join(ctx, 0);
	(void) duk_json_decode(ctx, 0);
	(void) duk_json_encode(ctx, 0);
	(void) duk_load_function(ctx);
	(void) duk_map_string(ctx, 0, NULL, NULL);
	(void) duk_new(ctx, 0);
	(void) duk_next(ctx, 0, 0);
	(void) duk_normalize_index(ctx, 0);
	(void) duk_pcall_method(ctx, 0);
	(void) duk_pcall_prop(ctx, 0, 0);
	(void) duk_pcall(ctx, 0);
	(void) duk_pcompile_lstring_filename(ctx, 0, "dummy", 0);
	(void) duk_pcompile_lstring(ctx, 0, "dummy", 0);
	(void) duk_pcompile_string_filename(ctx, 0, "dummy");
	(void) duk_pcompile_string(ctx, 0, "dummy");
	(void) duk_pcompile(ctx, 0);
	(void) duk_peval_lstring_noresult(ctx, "dummy", 0);
	(void) duk_peval_lstring(ctx, "dummy", 0);
	(void) duk_peval_noresult(ctx);
	(void) duk_peval_string_noresult(ctx, "dummy");
	(void) duk_peval_string(ctx, "dummy");
	(void) duk_peval(ctx);
	(void) duk_pnew(ctx, 0);
	(void) duk_pop_2(ctx);
	(void) duk_pop_3(ctx);
	(void) duk_pop_n(ctx, 0);
	(void) duk_pop(ctx);
	(void) duk_push_array(ctx);
	(void) duk_push_boolean(ctx, 0);
	(void) duk_push_buffer_object(ctx, 0, 0, 0, 0);
	(void) duk_push_buffer(ctx, 0, 0);
	(void) duk_push_c_function(ctx, NULL, 0);
	(void) duk_push_c_lightfunc(ctx, NULL, 0, 0, 0);
	(void) duk_push_context_dump(ctx);
	(void) duk_push_current_function(ctx);
	(void) duk_push_current_thread(ctx);
	(void) duk_push_dynamic_buffer(ctx, 0);
	(void) duk_push_error_object_va(ctx, 0, NULL, NULL);
	(void) duk_push_error_object(ctx, 0, "dummy");
	(void) duk_push_external_buffer(ctx);
	(void) duk_push_false(ctx);
	(void) duk_push_fixed_buffer(ctx, 0);
	(void) duk_push_global_object(ctx);
	(void) duk_push_global_stash(ctx);
	(void) duk_push_heap_stash(ctx);
	(void) duk_push_heapptr(ctx, NULL);
	(void) duk_push_int(ctx, 0);
	(void) duk_push_lstring(ctx, "dummy", 0);
	(void) duk_push_nan(ctx);
	(void) duk_push_null(ctx);
	(void) duk_push_number(ctx, 0.0);
	(void) duk_push_object(ctx);
	(void) duk_push_pointer(ctx, NULL);
	(void) duk_push_sprintf(ctx, "dummy");
	(void) duk_push_string(ctx, "dummy");
	(void) duk_push_this(ctx);
	(void) duk_push_thread_new_globalenv(ctx);
	(void) duk_push_thread_stash(ctx, NULL);
	(void) duk_push_thread(ctx);
	(void) duk_push_true(ctx);
	(void) duk_push_uint(ctx, 0);
	(void) duk_push_undefined(ctx);
	(void) duk_push_vsprintf(ctx, "dummy", NULL);
	(void) duk_put_function_list(ctx, 0, NULL);
	(void) duk_put_global_string(ctx, NULL);
	(void) duk_put_number_list(ctx, 0, NULL);
	(void) duk_put_prop_index(ctx, 0, 0);
	(void) duk_put_prop_string(ctx, 0, "dummy");
	(void) duk_put_prop(ctx, 0);
	(void) duk_realloc_raw(ctx, NULL, 0);
	(void) duk_realloc(ctx, NULL, 0);
	(void) duk_remove(ctx, 0);
	(void) duk_replace(ctx, 0);
	(void) duk_require_boolean(ctx, 0);
	(void) duk_require_buffer_data(ctx, 0, NULL);
	(void) duk_require_buffer(ctx, 0, NULL);
	(void) duk_require_c_function(ctx, 0);
	(void) duk_require_callable(ctx, 0);
	(void) duk_require_context(ctx, 0);
	(void) duk_require_function(ctx, 0);
	(void) duk_require_heapptr(ctx, 0);
	(void) duk_require_int(ctx, 0);
	(void) duk_require_lstring(ctx, 0, NULL);
	(void) duk_require_normalize_index(ctx, 0);
	(void) duk_require_null(ctx, 0);
	(void) duk_require_number(ctx, 0);
	(void) duk_require_object_coercible(ctx, 0);
	(void) duk_require_pointer(ctx, 0);
	(void) duk_require_stack_top(ctx, 0);
	(void) duk_require_stack(ctx, 0);
	(void) duk_require_string(ctx, 0);
	(void) duk_require_top_index(ctx);
	(void) duk_require_type_mask(ctx, 0, 0);
	(void) duk_require_uint(ctx, 0);
	(void) duk_require_undefined(ctx, 0);
	(void) duk_require_valid_index(ctx, 0);
	(void) duk_resize_buffer(ctx, 0, 0);
	(void) duk_safe_call(ctx, NULL, NULL, 0, 0);
	(void) duk_safe_to_lstring(ctx, 0, NULL);
	(void) duk_safe_to_string(ctx, 0);
	(void) duk_set_finalizer(ctx, 0);
	(void) duk_set_global_object(ctx);
	(void) duk_set_magic(ctx, 0, 0);
	(void) duk_set_prototype(ctx, 0);
	(void) duk_set_top(ctx, 0);
	(void) duk_steal_buffer(ctx, 0, NULL);
	(void) duk_strict_equals(ctx, 0, 0);
	(void) duk_substring(ctx, 0, 0, 0);
	(void) duk_swap_top(ctx, 0);
	(void) duk_swap(ctx, 0, 0);
	(void) duk_throw(ctx);
	(void) duk_to_boolean(ctx, 0);
	(void) duk_to_buffer(ctx, 0, NULL);
	(void) duk_to_defaultvalue(ctx, 0, 0);
	(void) duk_to_dynamic_buffer(ctx, 0, NULL);
	(void) duk_to_fixed_buffer(ctx, 0, NULL);
	(void) duk_to_int32(ctx, 0);
	(void) duk_to_int(ctx, 0);
	(void) duk_to_lstring(ctx, 0, NULL);
	(void) duk_to_null(ctx, 0);
	(void) duk_to_number(ctx, 0);
	(void) duk_to_object(ctx, 0);
	(void) duk_to_pointer(ctx, 0);
	(void) duk_to_primitive(ctx, 0, 0);
	(void) duk_to_string(ctx, 0);
	(void) duk_to_uint16(ctx, 0);
	(void) duk_to_uint32(ctx, 0);
	(void) duk_to_uint(ctx, 0);
	(void) duk_to_undefined(ctx, 0);
	(void) duk_trim(ctx, 0);
	(void) duk_xcopy_top(ctx, NULL, 0);
	(void) duk_xmove_top(ctx, NULL, 0);

	printf("never here\n"); fflush(stdout);
	return 0;
}
/* XXX: the implementation now assumes "chained" bound functions,
 * whereas "collapsed" bound functions (where there is ever only
 * one bound function which directly points to a non-bound, final
 * function) would require a "collapsing" implementation which
 * merges argument lists etc here.
 */
DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) {
	duk_hobject *h_bound;
	duk_hobject *h_target;
	duk_idx_t nargs;
	duk_idx_t i;

	/* vararg function, careful arg handling (e.g. thisArg may not be present) */
	nargs = duk_get_top(ctx);  /* = 1 + arg count */
	if (nargs == 0) {
		duk_push_undefined(ctx);
		nargs++;
	}
	DUK_ASSERT(nargs >= 1);

	duk_push_this(ctx);
	if (!duk_is_callable(ctx, -1)) {
		DUK_DDD(DUK_DDDPRINT("func is not callable"));
		goto type_error;
	}

	/* [ thisArg arg1 ... argN func ]  (thisArg+args == nargs total) */
	DUK_ASSERT_TOP(ctx, nargs + 1);

	/* create bound function object */
	duk_push_object_helper(ctx,
	                       DUK_HOBJECT_FLAG_EXTENSIBLE |
	                       DUK_HOBJECT_FLAG_BOUND |
	                       DUK_HOBJECT_FLAG_CONSTRUCTABLE |
	                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION),
	                       DUK_BIDX_FUNCTION_PROTOTYPE);
	h_bound = duk_get_hobject(ctx, -1);
	DUK_ASSERT(h_bound != NULL);

	/* [ thisArg arg1 ... argN func boundFunc ] */
	duk_dup(ctx, -2);  /* func */
	duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);

	duk_dup(ctx, 0);   /* thisArg */
	duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);

	duk_push_array(ctx);

	/* [ thisArg arg1 ... argN func boundFunc argArray ] */

	for (i = 0; i < nargs - 1; i++) {
		duk_dup(ctx, 1 + i);
		duk_put_prop_index(ctx, -2, i);
	}
	duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE);

	/* [ thisArg arg1 ... argN func boundFunc ] */

	/* bound function 'length' property is interesting */
	h_target = duk_get_hobject(ctx, -2);
	if (h_target == NULL ||  /* lightfunc */
	    DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) {
		/* For lightfuncs, simply read the virtual property. */
		duk_int_t tmp;
		duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH);
		tmp = duk_to_int(ctx, -1) - (nargs - 1);  /* step 15.a */
		duk_pop(ctx);
		duk_push_int(ctx, (tmp < 0 ? 0 : tmp));
	} else {
		duk_push_int(ctx, 0);
	}
	duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);  /* attrs in E5 Section 15.3.5.1 */

	/* caller and arguments must use the same thrower, [[ThrowTypeError]] */
	duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
	duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);

	/* these non-standard properties are copied for convenience */
	/* XXX: 'copy properties' API call? */
	duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
	duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC);
	duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME);
	duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);

	/* The 'strict' flag is copied to get the special [[Get]] of E5.1
	 * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
	 * function.  Not sure if this is correct, because the specification
	 * is a bit ambiguous on this point but it would make sense.
	 */
	if (h_target == NULL) {
		/* Lightfuncs are always strict. */
		DUK_HOBJECT_SET_STRICT(h_bound);
	} else if (DUK_HOBJECT_HAS_STRICT(h_target)) {
		DUK_HOBJECT_SET_STRICT(h_bound);
	}
	DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));

	return 1;

 type_error:
	return DUK_RET_TYPE_ERROR;
}
JavaScriptObject::JavaScriptObject(JavaTypeMap& typeMap, JNIEnv* env, duk_context* context,
                                   jstring name, jobjectArray methods)
    : m_name(JString(env, name).str())
    , m_context(context)
    , m_instance(nullptr)
    , m_nextFinalizer(nullptr) {
    CHECK_STACK(m_context);
    duk_push_global_object(m_context);
    if (!duk_get_prop_string(m_context, -1, m_name.c_str())) {
        duk_pop_2(m_context);
        throw std::invalid_argument("A global JavaScript object called " + m_name + " was not found");
    }

    m_instance = duk_get_heapptr(m_context, -1);
    if (m_instance == nullptr) {
        duk_pop_2(m_context);
        throw std::invalid_argument("JavaScript global called " + m_name + " is not an object");
    }

    // Make sure that the object has all of the methods we want.
    jmethodID getName = nullptr;
    const jsize numArgs = env->GetArrayLength(methods);
    for (jsize i = 0; i < numArgs; ++i) {
        auto method = env->GetObjectArrayElement(methods, i);
        if (getName == nullptr) {
            jclass methodClass = env->GetObjectClass(method);
            getName = env->GetMethodID(methodClass, "getName", "()Ljava/lang/String;");
        }

        // Sanity check that as of right now, the object we're proxying has a function with this name.
        const JString methodName(env, static_cast<jstring>(env->CallObjectMethod(method, getName)));
        if (!duk_get_prop_string(m_context, -1, methodName)) {
            duk_pop_3(m_context);
            throw std::runtime_error("JavaScript global " + m_name + " has no method called " +
                                     methodName.str());
        } else if (!duk_is_callable(m_context, -1)) {
            duk_pop_3(m_context);
            throw std::runtime_error("JavaScript property " + m_name + "." + methodName.str() +
                                     " not callable");
        }

        try {
            // Build a call wrapper that handles marshalling the arguments and return value.
            m_methods.emplace(std::make_pair(env->FromReflectedMethod(method),
                                             buildMethodBody(typeMap, env, method, methodName.str())));
        } catch (const std::invalid_argument& e) {
            duk_pop_3(m_context);
            throw std::invalid_argument("In proxied method \"" + m_name + "." + methodName.str() +
                                        "\": " + e.what());
        }

        // Pop the method property.
        duk_pop(m_context);
    }

    // Keep track of any previously registered finalizer.
    duk_get_finalizer(m_context, -1);
    m_nextFinalizer = duk_is_c_function(m_context, -1)
                      ? duk_get_c_function(m_context, -1)
                      : nullptr;
    duk_pop(m_context);
    duk_push_c_function(m_context, JavaScriptObject::finalizer, 1);
    duk_set_finalizer(m_context, -2);

    // Add 'this' to the list of pointers attached to the proxied instance.
    // TODO: don't use an array here, just use a separate hidden property for each proxy.
    if (!duk_has_prop_string(m_context, -1, WRAPPER_THIS_PROP_NAME)) {
        duk_push_array(m_context);
    } else {
        duk_get_prop_string(m_context, -1, WRAPPER_THIS_PROP_NAME);
    }

    const duk_size_t length = duk_get_length(m_context, -1);
    duk_push_pointer(m_context, this);
    duk_put_prop_index(m_context, -2, static_cast<duk_uarridx_t>(length));
    // Add the array (back) to the instance.
    duk_put_prop_string(m_context, -2, WRAPPER_THIS_PROP_NAME);

    // Pop the global and our instance.
    duk_pop_2(m_context);
}
Beispiel #19
0
void test(duk_context *ctx) {
	duk_idx_t i, n;

	/*
	 *  push test values
	 */

	/* 0 */
	duk_push_undefined(ctx);

	/* 1 */
	duk_push_null(ctx);

	/* 2 */
	duk_push_true(ctx);

	/* 3 */
	duk_push_false(ctx);

	/* 4 */
	duk_push_int(ctx, 123);

	/* 5 */
	duk_push_number(ctx, 123.4);

	/* 6 */
	duk_push_nan(ctx);

	/* 7 */
	duk_push_number(ctx, INFINITY);

	/* 8 */
	duk_push_number(ctx, -INFINITY);

	/* 9 */
	duk_push_string(ctx, "");

	/* 10 */
	duk_push_string(ctx, "foo");

	/* 11 */
	duk_push_object(ctx);

	/* 12 */
	duk_push_array(ctx);

	/* 13 */
	duk_push_c_function(ctx, my_c_func, DUK_VARARGS);

	/* 14 */
	duk_push_string(ctx, "(function() { print('hello'); })");
	duk_eval(ctx);

	/* 15 */
	duk_push_string(ctx, "escape.bind(null, 'foo')");
	duk_eval(ctx);

	/* 16 */
	duk_push_thread(ctx);

	/* 17 */
	duk_push_buffer(ctx, 1024, 0 /*dynamic*/);

	/* 18 */
	duk_push_buffer(ctx, 1024, 1 /*dynamic*/);

	/* 19 */
	duk_push_pointer(ctx, (void *) 0xf00);

	/*
	 *  call checkers for each
	 */

	n = duk_get_top(ctx);
	for (i = 0; i < n; i++) {
		printf("%02ld: ", (long) i);
		printf(" und=%d", (int) duk_is_undefined(ctx, i));
		printf(" null=%d", (int) duk_is_null(ctx, i));
		printf(" noru=%d", (int) duk_is_null_or_undefined(ctx, i));
		printf(" bool=%d", (int) duk_is_boolean(ctx, i));
		printf(" num=%d", (int) duk_is_number(ctx, i));
		printf(" nan=%d", (int) duk_is_nan(ctx, i));
		printf(" str=%d", (int) duk_is_string(ctx, i));
		printf(" obj=%d", (int) duk_is_object(ctx, i));
		printf(" arr=%d", (int) duk_is_array(ctx, i));
		printf(" fun=%d", (int) duk_is_function(ctx, i));
		printf(" cfun=%d", (int) duk_is_c_function(ctx, i));
		printf(" efun=%d", (int) duk_is_ecmascript_function(ctx, i));
		printf(" bfun=%d", (int) duk_is_bound_function(ctx, i));
		printf(" call=%d", (int) duk_is_callable(ctx, i));
		printf(" thr=%d", (int) duk_is_thread(ctx, i));
		printf(" buf=%d", (int) duk_is_buffer(ctx, i));
		printf(" dyn=%d", (int) duk_is_dynamic_buffer(ctx, i));
		printf(" fix=%d", (int) duk_is_fixed_buffer(ctx, i));
		printf(" ptr=%d", (int) duk_is_pointer(ctx, i));
		printf(" prim=%d", (int) duk_is_primitive(ctx, i));
		printf(" objcoerc=%d", (int) duk_is_object_coercible(ctx, i));
		printf("\n");
	}
}
Beispiel #20
0
int duk_bi_array_prototype_iter_shared(duk_context *ctx) {
	int len;
	int i;
	int k;
	int bval;
	int iter_type = duk_get_magic(ctx);
	duk_uint32_t res_length = 0;

	/* each call this helper serves has nargs==2 */
	DUK_ASSERT_TOP(ctx, 2);

	len = duk__push_this_obj_len_u32(ctx);
	if (!duk_is_callable(ctx, 0)) {
		goto type_error;
	}
	/* if thisArg not supplied, behave as if undefined was supplied */

	if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) {
		duk_push_array(ctx);
	} else {
		duk_push_undefined(ctx);
	}

	/* stack[0] = callback
	 * stack[1] = thisArg
	 * stack[2] = object
	 * stack[3] = ToUint32(length)  (unused, but avoid unnecessary pop)
	 * stack[4] = result array (or undefined)
	 */

	k = 0;  /* result index for filter() */
	for (i = 0; i < len; i++) {
		DUK_ASSERT_TOP(ctx, 5);

		if (!duk_get_prop_index(ctx, 2, i)) {
			duk_pop(ctx);
			continue;
		}

		/* The original value needs to be preserved for filter(), hence
		 * this funny order.  We can't re-get the value because of side
		 * effects.
		 */

		duk_dup(ctx, 0);
		duk_dup(ctx, 1);
		duk_dup(ctx, -3);
		duk_push_int(ctx, i);
		duk_dup(ctx, 2);  /* [ ... val callback thisArg val i obj ] */
		duk_call_method(ctx, 3); /* -> [ ... val retval ] */

		switch (iter_type) {
		case DUK__ITER_EVERY:
			bval = duk_to_boolean(ctx, -1);
			if (!bval) {
				/* stack top contains 'false' */
				return 1;
			}
			break;
		case DUK__ITER_SOME:
			bval = duk_to_boolean(ctx, -1);
			if (bval) {
				/* stack top contains 'true' */
				return 1;
			}
			break;
		case DUK__ITER_FOREACH:
			/* nop */
			break;
		case DUK__ITER_MAP:
			duk_dup(ctx, -1);
			duk_def_prop_index(ctx, 4, i, DUK_PROPDESC_FLAGS_WEC);  /* retval to result[i] */
			res_length = i + 1;
			break;
		case DUK__ITER_FILTER:
			bval = duk_to_boolean(ctx, -1);
			if (bval) {
				duk_dup(ctx, -2);  /* orig value */
				duk_def_prop_index(ctx, 4, k, DUK_PROPDESC_FLAGS_WEC);
				k++;
				res_length = k;
			}
			break;
		default:
			DUK_UNREACHABLE();
			break;
		}
		duk_pop_2(ctx);

		DUK_ASSERT_TOP(ctx, 5);
	}

	switch (iter_type) {
	case DUK__ITER_EVERY:
		duk_push_true(ctx);
		break;
	case DUK__ITER_SOME:
		duk_push_false(ctx);
		break;
	case DUK__ITER_FOREACH:
		duk_push_undefined(ctx);
		break;
	case DUK__ITER_MAP:
	case DUK__ITER_FILTER:
		DUK_ASSERT_TOP(ctx, 5);
		DUK_ASSERT(duk_is_array(ctx, -1));  /* topmost element is the result array already */
		duk_push_number(ctx, (double) res_length);  /* FIXME */
		duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
		break;
	default:
		DUK_UNREACHABLE();
		break;
	}

	return 1;

 type_error:
	return DUK_RET_TYPE_ERROR;
}
Beispiel #21
0
DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
	/*
	 *  There are two [[Construct]] operations in the specification:
	 *
	 *    - E5 Section 13.2.2: for Function objects
	 *    - E5 Section 15.3.4.5.2: for "bound" Function objects
	 *
	 *  The chain of bound functions is resolved in Section 15.3.4.5.2,
	 *  with arguments "piling up" until the [[Construct]] internal
	 *  method is called on the final, actual Function object.  Note
	 *  that the "prototype" property is looked up *only* from the
	 *  final object, *before* calling the constructor.
	 *
	 *  Currently we follow the bound function chain here to get the
	 *  "prototype" property value from the final, non-bound function.
	 *  However, we let duk_handle_call() handle the argument "piling"
	 *  when the constructor is called.  The bound function chain is
	 *  thus now processed twice.
	 *
	 *  When constructing new Array instances, an unnecessary object is
	 *  created and discarded now: the standard [[Construct]] creates an
	 *  object, and calls the Array constructor.  The Array constructor
	 *  returns an Array instance, which is used as the result value for
	 *  the "new" operation; the object created before the Array constructor
	 *  call is discarded.
	 *
	 *  This would be easy to fix, e.g. by knowing that the Array constructor
	 *  will always create a replacement object and skip creating the fallback
	 *  object in that case.
	 *
	 *  Note: functions called via "new" need to know they are called as a
	 *  constructor.  For instance, built-in constructors behave differently
	 *  depending on how they are called.
	 */

	/* XXX: merge this with duk_js_call.c, as this function implements
	 * core semantics (or perhaps merge the two files altogether).
	 */

	duk_hthread *thr = (duk_hthread *) ctx;
	duk_hobject *proto;
	duk_hobject *cons;
	duk_hobject *fallback;
	duk_idx_t idx_cons;
	duk_small_uint_t call_flags;

	DUK_ASSERT_CTX_VALID(ctx);

	/* [... constructor arg1 ... argN] */

	idx_cons = duk_require_normalize_index(ctx, -nargs - 1);

	DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld",
	                     (long) duk_get_top(ctx), (long) nargs, (long) idx_cons));

	/* XXX: code duplication */

	/*
	 *  Figure out the final, non-bound constructor, to get "prototype"
	 *  property.
	 */

	duk_dup(ctx, idx_cons);
	for (;;) {
		duk_tval *tv;
		tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
		DUK_ASSERT(tv != NULL);

		if (DUK_TVAL_IS_OBJECT(tv)) {
			cons = DUK_TVAL_GET_OBJECT(tv);
			DUK_ASSERT(cons != NULL);
			if (!DUK_HOBJECT_IS_CALLABLE(cons) || !DUK_HOBJECT_HAS_CONSTRUCTABLE(cons)) {
				/* Checking callability of the immediate target
				 * is important, same for constructability.
				 * Checking it for functions down the bound
				 * function chain is not strictly necessary
				 * because .bind() should normally reject them.
				 * But it's good to check anyway because it's
				 * technically possible to edit the bound function
				 * chain via internal keys.
				 */
				goto not_constructable;
			}
			if (!DUK_HOBJECT_HAS_BOUNDFUNC(cons)) {
				break;
			}
		} else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
			/* Lightfuncs cannot be bound. */
			break;
		} else {
			/* Anything else is not constructable. */
			goto not_constructable;
		}
		duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TARGET);  /* -> [... cons target] */
		duk_remove_m2(ctx);                                         /* -> [... target] */
	}
	DUK_ASSERT(duk_is_callable(ctx, -1));
	DUK_ASSERT(duk_is_lightfunc(ctx, -1) ||
	           (duk_get_hobject(ctx, -1) != NULL && !DUK_HOBJECT_HAS_BOUNDFUNC(duk_get_hobject(ctx, -1))));

	/* [... constructor arg1 ... argN final_cons] */

	/*
	 *  Create "fallback" object to be used as the object instance,
	 *  unless the constructor returns a replacement value.
	 *  Its internal prototype needs to be set based on "prototype"
	 *  property of the constructor.
	 */

	duk_push_object(ctx);  /* class Object, extensible */

	/* [... constructor arg1 ... argN final_cons fallback] */

	duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_PROTOTYPE);
	proto = duk_get_hobject(ctx, -1);
	if (!proto) {
		DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
		                     "-> leave standard Object prototype as fallback prototype"));
	} else {
		DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
		                     "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
		fallback = duk_get_hobject(ctx, -2);
		DUK_ASSERT(fallback != NULL);
		DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
	}
	duk_pop(ctx);

	/* [... constructor arg1 ... argN final_cons fallback] */

	/*
	 *  Manipulate callstack for the call.
	 */

	duk_dup_top(ctx);
	duk_insert(ctx, idx_cons + 1);  /* use fallback as 'this' value */
	duk_insert(ctx, idx_cons);      /* also stash it before constructor,
	                                 * in case we need it (as the fallback value)
	                                 */
	duk_pop(ctx);                   /* pop final_cons */


	/* [... fallback constructor fallback(this) arg1 ... argN];
	 * Note: idx_cons points to first 'fallback', not 'constructor'.
	 */

	DUK_DDD(DUK_DDDPRINT("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, "
	                     "nargs=%ld, top=%ld",
	                     (duk_tval *) duk_get_tval(ctx, idx_cons + 1),
	                     (duk_tval *) duk_get_tval(ctx, idx_cons + 2),
	                     (long) nargs,
	                     (long) duk_get_top(ctx)));

	/*
	 *  Call the constructor function (called in "constructor mode").
	 */

	call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL;  /* not protected, respect reclimit, is a constructor call */

	duk_handle_call_unprotected(thr,           /* thread */
	                            nargs,         /* num_stack_args */
	                            call_flags);   /* call_flags */

	/* [... fallback retval] */

	DUK_DDD(DUK_DDDPRINT("constructor call finished, fallback=%!iT, retval=%!iT",
	                     (duk_tval *) duk_get_tval(ctx, -2),
	                     (duk_tval *) duk_get_tval(ctx, -1)));

	/*
	 *  Determine whether to use the constructor return value as the created
	 *  object instance or not.
	 */

	if (duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT |
	                                 DUK_TYPE_MASK_BUFFER |
	                                 DUK_TYPE_MASK_LIGHTFUNC)) {
		duk_remove_m2(ctx);
	} else {
		duk_pop(ctx);
	}

	/*
	 *  Augment created errors upon creation (not when they are thrown or
	 *  rethrown).  __FILE__ and __LINE__ are not desirable here; the call
	 *  stack reflects the caller which is correct.
	 */

#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
	duk_hthread_sync_currpc(thr);
	duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
#endif

	/* [... retval] */

	return;

 not_constructable:
#if defined(DUK_USE_VERBOSE_ERRORS)
#if defined(DUK_USE_PARANOID_ERRORS)
	DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_get_type_name(ctx, -1));
#else
	DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_push_string_readable(ctx, -1));
#endif
#else
	DUK_ERROR_TYPE(thr, "not constructable");
#endif
}
Beispiel #22
0
int duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
	int nargs;
	int have_acc;
	int i, len;
	int idx_step = duk_get_magic(ctx);  /* idx_step is +1 for reduce, -1 for reduceRight */

	/* We're a varargs function because we need to detect whether
	 * initialValue was given or not.
	 */
	nargs = duk_get_top(ctx);
	DUK_DDD(DUK_DDDPRINT("nargs=%d", nargs));

	duk_set_top(ctx, 2);
	len = duk__push_this_obj_len_u32(ctx);
	if (!duk_is_callable(ctx, 0)) {
		goto type_error;
	}

	/* stack[0] = callback fn
	 * stack[1] = initialValue
	 * stack[2] = object (coerced this)
	 * stack[3] = length (not needed, but not popped above)
	 * stack[4] = accumulator
	 */

	have_acc = 0;
	if (nargs >= 2) {
		duk_dup(ctx, 1);
		have_acc = 1;
	}
	DUK_DDD(DUK_DDDPRINT("have_acc=%d, acc=%!T", have_acc, duk_get_tval(ctx, 3)));

	for (i = (idx_step >= 0 ? 0 : len - 1);
	     i >= 0 && i < len;
	     i += idx_step) {
		DUK_DDD(DUK_DDDPRINT("i=%d, len=%d, have_acc=%d, top=%d, acc=%!T",
		                     i, len, have_acc, duk_get_top(ctx), duk_get_tval(ctx, 4)));

		DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) ||
		           (!have_acc && duk_get_top(ctx) == 4));

		if (!duk_has_prop_index(ctx, 2, i)) {
			continue;
		}

		if (!have_acc) {
			DUK_ASSERT_TOP(ctx, 4);
			duk_get_prop_index(ctx, 2, i);
			have_acc = 1;
			DUK_ASSERT_TOP(ctx, 5);
		} else {
			DUK_ASSERT_TOP(ctx, 5);
			duk_dup(ctx, 0);
			duk_dup(ctx, 4);
			duk_get_prop_index(ctx, 2, i);
			duk_push_int(ctx, i);  /* FIXME: type */
			duk_dup(ctx, 2);
			DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T",
			                     duk_get_tval(ctx, -5), duk_get_tval(ctx, -4), duk_get_tval(ctx, -3),
			                     duk_get_tval(ctx, -2), duk_get_tval(ctx, -1)));
			duk_call(ctx, 4);
			DUK_DDD(DUK_DDDPRINT("-> result: %!T", duk_get_tval(ctx, -1)));
			duk_replace(ctx, 4);
			DUK_ASSERT_TOP(ctx, 5);
		}
	}

	if (!have_acc) {
		goto type_error;
	}

	DUK_ASSERT_TOP(ctx, 5);
	return 1;

 type_error:
	return DUK_RET_TYPE_ERROR;
}
Beispiel #23
0
duk_bool_t dschema_is_continuation(duk_context* ctx, duk_idx_t index) {
  return !duk_is_valid_index(ctx, index) ||
          duk_is_callable(ctx, index) ||
          duk_is_undefined(ctx, index);
}
Beispiel #24
0
static int r2plugin(duk_context *ctx) {
	RLibStruct *lib_struct;
	int ret = R_TRUE;
	// args: type, function
	const char *type = duk_require_string (ctx, 0);
	if (strcmp (type, "asm")) {
		eprintf ("TODO: duk.r2plugin only supports 'asm' plugins atm\n");
		return R_FALSE;
	}
	// call function of 2nd parameter, or get object
	if (duk_is_function (ctx, 1)) {
		duk_push_string (ctx, "TODO"); // TODO: this must be the RAsm object to get bits, offset, ..
		duk_call (ctx, 1);
		duk_to_object (ctx, 1);
	}
	if (!duk_is_object (ctx, 1)) {
		eprintf ("Expected object or function\n");
		return R_FALSE;
	}
	duk_to_object (ctx, 1);
	#define ap asm_plugin
	ap = R_NEW0 (RAsmPlugin);

#define GETSTR(x,y,or) \
	duk_dup_top (ctx); \
	duk_get_prop_string (ctx, 1, y); \
	if (or) { \
		const char *str = duk_to_string (ctx, -1); \
		x = mystrdup (str? str: or); \
	} else { \
		x = mystrdup (duk_require_string (ctx, -1)); \
	} \
	duk_pop (ctx);

#define GETINT(x,y,or) \
	duk_dup_top (ctx); \
	duk_get_prop_string (ctx, 1, y); \
	if (or) { \
		x = duk_is_number (ctx, -1)? \
			duk_to_int (ctx, -1): or; \
	} else { \
		x = duk_require_int (ctx, -1); \
	} \
	duk_pop (ctx);

#define GETFUN(x,y) \
	duk_dup_top (ctx); \
	duk_get_prop_string (ctx, 1, y); \
	x = duk_require_tval (ctx, 1); \
	duk_pop (ctx);

	// mandatory
	GETSTR (ap->name, "name", NULL);
	GETSTR (ap->arch, "arch", NULL);
	// optional
	GETSTR (ap->license, "license", "unlicensed");
	GETSTR (ap->desc, "description", "JS Disasm Plugin");
	GETINT (ap->bits, "bits", 32);
	// mandatory unless we handle asm+disasm
	ap->user = duk_require_tval (ctx, -1);
	//ap->user = duk_dup_top (ctx); // clone object inside user
	//GETFUN (ap->user, "disassemble");
	duk_push_global_stash(ctx);
	duk_get_prop_string (ctx, 1, "disassemble");
	duk_put_prop_string(ctx, -2, "disfun"); // TODO: prefix plugin name somehow
	ap->disassemble = duk_disasm;

	duk_push_global_stash(ctx);
	duk_get_prop_string (ctx, 1, "assemble");
	duk_put_prop_string(ctx, -2, "asmfun"); // TODO: prefix plugin name somehow
	ap->assemble = duk_assemble;

#if 0
	duk_get_prop_string (ctx, 1, "disassemble");
	duk_push_string (ctx, "WINRAR");
	duk_call (ctx, 1);
#endif
#if 0
	duk_get_prop_string (ctx, 1, "disassemble");
	void *a = duk_require_tval (ctx, -1);
	if (duk_is_callable (ctx, -1)) {
		ut8 *b = a;
		eprintf ("IS FUNCTION %02x %02x \n", b[0], b[1]);
	} else eprintf ("NOT CALLABLE\n");
	ap->user = a;
	eprintf ("---- %p\n", a);
	duk_push_string (ctx, "F**K YOU");
	//duk_dup_top(ctx);
	//duk_call_method (ctx, 0);
	duk_call (ctx, 1);
	duk_push_tval (ctx, ap->user); // push fun
	duk_push_string (ctx, "WINRAR");
	duk_call (ctx, 1);
	duk_pop (ctx);
#endif

	// TODO: add support to assemble from js too
	//ap->assemble = duk_disasm;
	#define lp lib_struct
	lp = R_NEW0 (RLibStruct);
	lp->type = R_LIB_TYPE_ASM; // TODO resolve from handler
	lp->data = ap;
	r_lib_open_ptr (Gcore->lib, "duktape.js", NULL, lp);
	duk_push_boolean (ctx, ret);
	return 1;
}
Beispiel #25
0
/* FIXME: the implementation now assumes "chained" bound functions,
 * whereas "collapsed" bound functions (where there is ever only
 * one bound function which directly points to a non-bound, final
 * function) would require a "collapsing" implementation which
 * merges argument lists etc here.
 */
int duk_bi_function_prototype_bind(duk_context *ctx) {
	duk_hobject *h_target;
	int nargs;
	int i;

	/* FIXME: stack checks */

	/* vararg function, careful arg handling (e.g. thisArg may not be present) */
	nargs = duk_get_top(ctx);  /* = 1 + arg count */
	if (nargs == 0) {
		duk_push_undefined(ctx);
		nargs++;
	}
	DUK_ASSERT(nargs >= 1);

	duk_push_this(ctx);
	if (!duk_is_callable(ctx, -1)) {
		DUK_DDD(DUK_DDDPRINT("func is not callable"));
		goto type_error;
	}

	/* [ thisArg arg1 ... argN func ]  (thisArg+args == nargs total) */
	DUK_ASSERT_TOP(ctx, nargs + 1);

	/* create bound function object */
	duk_push_object_helper(ctx,
	                       DUK_HOBJECT_FLAG_EXTENSIBLE |
	                       DUK_HOBJECT_FLAG_BOUND |
	                       DUK_HOBJECT_FLAG_CONSTRUCTABLE |
	                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION),
	                       DUK_BIDX_FUNCTION_PROTOTYPE);

	/* FIXME: check hobject flags (e.g. strict) */

	/* [ thisArg arg1 ... argN func boundFunc ] */
	duk_dup(ctx, -2);  /* func */
	duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);

	duk_dup(ctx, 0);   /* thisArg */
	duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);

	duk_push_array(ctx);

	/* [ thisArg arg1 ... argN func boundFunc argArray ] */

	for (i = 0; i < nargs - 1; i++) {
		duk_dup(ctx, 1 + i);
		duk_put_prop_index(ctx, -2, i);
	}
	duk_def_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE);

	/* [ thisArg arg1 ... argN func boundFunc ] */

	/* bound function 'length' property is interesting */
	h_target = duk_get_hobject(ctx, -2);
	DUK_ASSERT(h_target != NULL);
	if (DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) {
		int tmp;
		duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH);
		tmp = duk_to_int(ctx, -1) - (nargs - 1);  /* step 15.a */
		duk_pop(ctx);
		duk_push_int(ctx, (tmp < 0 ? 0 : tmp));
	} else {
		duk_push_int(ctx, 0);
	}
	duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);  /* attrs in E5 Section 15.3.5.1 */

	/* caller and arguments must use the same thrower, [[ThrowTypeError]] */
	duk_def_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
	duk_def_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);

	/* these non-standard properties are copied for convenience */
	/* FIXME: 'copy properties' API call? */
	duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
	duk_def_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC);
	duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME);
	duk_def_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);

	DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", duk_get_tval(ctx, -1)));

	return 1;

 type_error:
	return DUK_RET_TYPE_ERROR;
}
Beispiel #26
0
DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
	duk_idx_t nargs;
	duk_bool_t have_acc;
	duk_uint32_t i, len;
	duk_small_int_t idx_step = duk_get_current_magic(ctx);  /* idx_step is +1 for reduce, -1 for reduceRight */

	/* We're a varargs function because we need to detect whether
	 * initialValue was given or not.
	 */
	nargs = duk_get_top(ctx);
	DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs));

	duk_set_top(ctx, 2);
	len = duk__push_this_obj_len_u32(ctx);
	if (!duk_is_callable(ctx, 0)) {
		goto type_error;
	}

	/* stack[0] = callback fn
	 * stack[1] = initialValue
	 * stack[2] = object (coerced this)
	 * stack[3] = length (not needed, but not popped above)
	 * stack[4] = accumulator
	 */

	have_acc = 0;
	if (nargs >= 2) {
		duk_dup(ctx, 1);
		have_acc = 1;
	}
	DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T",
	                     (long) have_acc, (duk_tval *) duk_get_tval(ctx, 3)));

	/* For len == 0, i is initialized to len - 1 which underflows.
	 * The condition (i < len) will then exit the for-loop on the
	 * first round which is correct.  Similarly, loop termination
	 * happens by i underflowing.
	 */

	for (i = (idx_step >= 0 ? 0 : len - 1);
	     i < len;  /* i >= 0 would always be true */
	     i += idx_step) {
		DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T",
		                     (long) i, (long) len, (long) have_acc,
		                     (long) duk_get_top(ctx),
		                     (duk_tval *) duk_get_tval(ctx, 4)));

		DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) ||
		           (!have_acc && duk_get_top(ctx) == 4));

		if (!duk_has_prop_index(ctx, 2, (duk_uarridx_t) i)) {
			continue;
		}

		if (!have_acc) {
			DUK_ASSERT_TOP(ctx, 4);
			duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
			have_acc = 1;
			DUK_ASSERT_TOP(ctx, 5);
		} else {
			DUK_ASSERT_TOP(ctx, 5);
			duk_dup(ctx, 0);
			duk_dup(ctx, 4);
			duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
			duk_push_u32(ctx, i);
			duk_dup(ctx, 2);
			DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T",
			                     (duk_tval *) duk_get_tval(ctx, -5), (duk_tval *) duk_get_tval(ctx, -4),
			                     (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
			                     (duk_tval *) duk_get_tval(ctx, -1)));
			duk_call(ctx, 4);
			DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
			duk_replace(ctx, 4);
			DUK_ASSERT_TOP(ctx, 5);
		}
	}

	if (!have_acc) {
		goto type_error;
	}

	DUK_ASSERT_TOP(ctx, 5);
	return 1;

 type_error:
	return DUK_RET_TYPE_ERROR;
}