Esempio n. 1
0
// Assumes nargs are the top of the stack.  Rest comes from request
// Return value is not left on the stack.
void duv_resolve(uv_req_t* req, int nargs) {
  duk_context *ctx = req->data;
  duv_push_handle(ctx, req);
  // stack: args... obj
  duk_get_prop_string(ctx, -1, "\xff""uv-callback");
  // stack: args... obj callback
  duk_del_prop_string(ctx, -2, "\xff""uv-callback");
  // stack: args... obj callback

  if (!duk_is_function(ctx, -1)) {
    // stack: args... obj callback
    duk_pop_n(ctx, 2 + nargs);
    return;
  }
  duk_remove(ctx, -2);
  // stack: args... callback
  duk_insert(ctx, -(nargs + 1));
  // stack: callback args...
  duk_call(ctx, nargs);
  // stack: result
  duk_pop(ctx);

  // Remove the request from the GC roots
  duv_remove_handle(ctx, req);
}
Esempio n. 2
0
void *
es_get_native_obj(duk_context *ctx, int obj_idx, es_native_type_t wanted_type)
{
  duk_get_finalizer(ctx, obj_idx);

  if(!duk_is_function(ctx, -1)) {
    duk_error(ctx, DUK_ERR_ERROR, "Object is not of type %s (no finalizer)",
              native_type_to_str(wanted_type));
  }

  es_native_type_t current_type = duk_get_magic(ctx, -1);

  duk_pop(ctx);

  if(current_type != wanted_type)
    duk_error(ctx, DUK_ERR_ERROR, "Object is %s, expected %s",
              native_type_to_str(current_type),
              native_type_to_str(wanted_type));

  duk_get_prop_string(ctx, obj_idx, PTRNAME);
  if(!duk_is_pointer(ctx, -1))
    duk_error(ctx, DUK_ERR_ERROR, "Object missing ptr");

  void *r = duk_get_pointer(ctx, -1);
  duk_pop(ctx);
  return r;
}
Esempio n. 3
0
void test(duk_context *ctx) {
	duk_idx_t i, n;

	duk_push_undefined(ctx);
	duk_push_null(ctx);
	duk_push_boolean(ctx, 0);
	duk_push_boolean(ctx, 123);
	duk_push_number(ctx, 234);
	duk_push_string(ctx, "foo");
	duk_push_object(ctx);
	duk_push_array(ctx);
	duk_push_c_function(ctx, my_c_func, DUK_VARARGS);
	duk_push_fixed_buffer(ctx, 1024);
	duk_push_dynamic_buffer(ctx, 1024);
	duk_push_pointer(ctx, (void *) 0xdeadbeefUL);

	n = duk_get_top(ctx);
	for (i = 0; i < n + 1; i++) {  /* end on invalid index on purpose */
		duk_int_t typeval, typemask;

		typeval = duk_get_type(ctx, i);
		typemask = duk_get_type_mask(ctx, i);

		printf("stack[%ld] --> type=%ld mask=0x%08lx ",
		       (long) i, (long) typeval, (long) typemask);

		switch(duk_get_type(ctx, i)) {
		case DUK_TYPE_NONE:       printf("none"); break;
		case DUK_TYPE_UNDEFINED:  printf("undefined"); break;
		case DUK_TYPE_NULL:       printf("null"); break;
		case DUK_TYPE_BOOLEAN:    printf("boolean"); break;
		case DUK_TYPE_NUMBER:     printf("number"); break;
		case DUK_TYPE_STRING:     printf("string"); break;
		case DUK_TYPE_OBJECT:     printf("object"); break;
		case DUK_TYPE_BUFFER:     printf("buffer"); break;
		case DUK_TYPE_POINTER:    printf("pointer"); break;
		default:                  printf("unknown(%d)", (int) duk_get_type(ctx, i)); break;
		}

		printf(" bool=%d num=%lf str=%s buf-is-null=%d ptr=%p",
		       (int) duk_get_boolean(ctx, i),
		       (double) duk_get_number(ctx, i),
		       duk_get_string(ctx, i),
		       (duk_get_buffer(ctx, i, NULL) == NULL ? 1 : 0),
		       duk_get_pointer(ctx, i));

		printf(" isobj=%d isarr=%d isfunc=%d",
		       (int) duk_is_object(ctx, i),
		       (int) duk_is_array(ctx, i),
		       (int) duk_is_function(ctx, i));

		printf("\n");
	}
}
Esempio n. 4
0
gboolean
_gum_duk_parse_bytes (duk_context * ctx,
                      duk_idx_t index,
                      GBytes ** bytes)
{
  gpointer data;
  duk_size_t size;

  data = duk_get_buffer_data (ctx, index, &size);
  if (data != NULL)
  {
    *bytes = g_bytes_new (data, size);
    return TRUE;
  }
  else if (duk_is_array (ctx, index))
  {
    duk_size_t i;

    duk_get_prop_string (ctx, index, "length");
    size = duk_get_uint (ctx, -1);
    duk_pop (ctx);

    if (size >= GUM_MAX_JS_BYTE_ARRAY_LENGTH)
      return FALSE;

    data = g_malloc (size);

    for (i = 0; i != size; i++)
    {
      duk_get_prop_index (ctx, index, (duk_uarridx_t) i);
      ((guint8 *) data)[i] = duk_get_uint (ctx, -1) & 0xff;
      duk_pop (ctx);
    }

    *bytes = g_bytes_new_take (data, size);
    return TRUE;
  }
  else if (duk_is_null_or_undefined (ctx, index) ||
      duk_is_boolean (ctx, index) ||
      duk_is_number (ctx, index) ||
      duk_is_nan (ctx, index) ||
      duk_is_string (ctx, index) ||
      duk_is_function (ctx, index))
  {
    return FALSE;
  }

  *bytes = g_bytes_new (NULL, 0);
  return TRUE;
}
static duk_ret_t my_func(duk_context *ctx) {
    duk_c_function funcptr;

    printf("my_func, top=%ld\n", (long) duk_get_top(ctx));

    duk_push_current_function(ctx);
    printf("type=%d\n", (int) duk_get_type(ctx, -1));
    printf("duk_is_object: %d\n", (int) duk_is_object(ctx, -1));
    printf("duk_is_function: %d\n", (int) duk_is_function(ctx, -1));

    funcptr = duk_get_c_function(ctx, -1);
    printf("duk_get_c_function matches my_func: %d\n", (my_func == funcptr ? 1 : 0));

    printf("final top: %ld\n", (long) duk_get_top(ctx));
    return 0;
}
Esempio n. 6
0
duk_ret_t js_discovery(duk_context *ctx)
{
   int ret;
   int startDelay = 1;
   ph->ssdp = true;
   const char *str = duk_require_string(ctx, 0);
   if (!duk_is_function(ctx, 1)) {                                            
       duk_error(ctx, DUK_ERR_TYPE_ERROR, "Function required for callback");
   }        
   duk_dup(ctx, 1);
   finishCallback = duv_ref(ctx); 

   setDiscovery();
   run_callback = true;

   slog(DEBUG,DEBUG,"SSDP callback saved.");
   return 0;
}
Esempio n. 7
0
/*
 * Setup a libuv request.
 */
mn_req_t *
mn_setup_req(duk_context *ctx, int callback_index) {
	mn_req_t *data = duk_alloc(ctx, sizeof(*data));
	duk_push_this(ctx);
	data->context = mn_ref(ctx);
	duk_dup(ctx, -1);
	data->req_ref = mn_ref(ctx);

	if (duk_is_function(ctx, callback_index)) {
		duk_dup(ctx, callback_index);
		data->callback_ref = mn_ref(ctx);
	} else {
		data->callback_ref = 0;
	}

	data->data_ref = 0;
	data->data = NULL;
	return data;
}
Esempio n. 8
0
void duv_emit(uv_handle_t* handle, const char* key, int nargs, int cleanup) {
  duk_context *ctx = handle->data;
  duv_push_handle(ctx, handle);
  // stack: args... this
  duk_get_prop_string(ctx, -1, key);
  // stack: args... this fn
  if (cleanup) duk_del_prop_string(ctx, -2, key);
  // stack: args... this fn
  if (!duk_is_function(ctx, -1)) {
    duk_pop_n(ctx, 2 + nargs);
    return;
  }
  duk_insert(ctx, -(nargs + 2));
  // stack: fn args... this
  duk_insert(ctx, -(nargs + 1));
  // stack: fn this args...
  duk_call_method(ctx, nargs);
  // stack: result
  duk_pop(ctx);
}
void test(duk_context *ctx) {
    duk_ret_t rc;

    /* first test what happens when there is no running function */

    printf("no running function\n");
    duk_push_current_function(ctx);
    printf("type=%d\n", (int) duk_get_type(ctx, -1));
    printf("duk_is_object: %d\n", (int) duk_is_object(ctx, -1));
    printf("duk_is_function: %d\n", (int) duk_is_function(ctx, -1));
    duk_pop(ctx);

    /* then test the basic case */

    printf("basic case\n");
    duk_push_c_function(ctx, my_func, 1 /*nargs*/);
    duk_push_int(ctx, 123);
    rc = duk_pcall(ctx, 1);
    printf("rc=%d, result='%s'\n", (int) rc, duk_to_string(ctx, -1));
    duk_pop(ctx);
}
Esempio n. 10
0
static int SetTriggerCallback(duk_context* ctx, int pinFunc, int debounce)
{
    AJ_Status status;
    int32_t trigId;
    AJS_IO_PinTriggerCondition condition = (AJS_IO_PinTriggerCondition)duk_require_int(ctx, 0);

    if (condition == AJS_IO_PIN_TRIGGER_DISABLE) {
        /*
         * For backwards compatibility
         */
        return ClearTriggerCallback(ctx, pinFunc, condition);
    }
    if (!duk_is_function(ctx, 1)) {
        duk_error(ctx, DUK_ERR_TYPE_ERROR, "Trigger function required");
    }
    /*
     * Enable the trigger
     */
    status = AJS_TargetIO_PinEnableTrigger(PinCtxPtr(ctx), pinFunc, condition, &trigId, debounce);
    if (status != AJ_OK) {
        duk_error(ctx, DUK_ERR_INTERNAL_ERROR, "Error %s", AJ_StatusText(status));
    }
    duk_get_global_string(ctx, AJS_IOObjectName);
    duk_get_prop_string(ctx, -1, AJS_HIDDEN_PROP("trigs"));
    /*
     * Set the callback function on the pin object
     */
    duk_push_this(ctx);
    duk_dup(ctx, 1);
    duk_put_prop_string(ctx, -2, "trigger");
    /*
     * Add the pin object to the triggers array.
     */
    duk_put_prop_index(ctx, -2, trigId);
    duk_pop_2(ctx);
    /*
     * Leave pin object on the stack
     */
    return 1;
}
Esempio n. 11
0
JNIEXPORT jobject JNICALL Java_com_furture_react_DuktapeEngine_nativeCallJSRef
  (JNIEnv *env, jobject thisObject, jlong ptr, jint jsRef, jstring proxyMethod, jobjectArray args){
   duk_context *ctx  = convert_to_context(ptr);
   DEBUG_LOG("ScriptEngine","Java_com_furture_react_DuktapeEngine_nativeCallJSRef start %d", duk_get_top(ctx));
   duk_push_js_ref(ctx, jsRef);
   if(duk_is_function(ctx, -1)){
	      DEBUG_LOG("ScriptEngine","Java_com_furture_react_DuktapeEngine_nativeCallJSRef is Function %d", jsRef);
	   	  jsize length = duk_push_java_object_array(ctx, env, args);
	   	   DEBUG_LOG("ScriptEngine","Java_com_furture_react_DuktapeEngine_nativeCallJSRef call  Function %d", length);
		  if(duk_pcall(ctx, length) != DUK_EXEC_SUCCESS){
			  jboolean iscopy = JNI_FALSE;
			  const char* method = ((*env)->GetStringUTFChars(env, proxyMethod, &iscopy));
			  LOGE("ScriptEngine","ScriptEngine CallJSRef   %s method exception %s", method, duk_js_error_to_string(ctx, -1));
			  duk_pop(ctx);
			  duk_push_null(ctx);
			  if(method != NULL){
			     (*env)->ReleaseStringUTFChars(env, proxyMethod, method);
			  }
		  }
		  DEBUG_LOG("ScriptEngine","Java_com_furture_react_DuktapeEngine_nativeCallJSRef call  Function %d", length);
		  jobject  value =  duk_to_java_object(ctx, env, -1);
		  duk_pop(ctx);
		  return value;
   }
   jboolean iscopy = JNI_FALSE;
   const char* method = ((*env)->GetStringUTFChars(env, proxyMethod, &iscopy));
   duk_push_string(ctx, method);
   jsize length = duk_push_java_object_array(ctx, env, args);
   DEBUG_LOG("ScriptEngine","Java_com_furture_react_DuktapeEngine_nativeCallJSRef call Object  Function %d", length);
   if(duk_pcall_prop(ctx, -2 - length, length) != DUK_EXEC_SUCCESS){
	   LOGE("ScriptEngine","ScriptEngine CallJSRef  %d proxy method %s exception %s", jsRef, method, duk_js_error_to_string(ctx, -1));
	   duk_pop(ctx);
	   duk_push_null(ctx);
   }
   (*env)->ReleaseStringUTFChars(env, proxyMethod, method);
   DEBUG_LOG("ScriptEngine","Java_com_furture_react_DuktapeEngine_nativeCallJSRef call Object success %d", duk_get_type(ctx, -1));
   jobject  value =  duk_to_java_object(ctx, env, -1);
   duk_pop_2(ctx);
   return value;
}
Esempio n. 12
0
duk_bool_t dschema_is_continuation(duk_context* ctx, duk_idx_t index) {
  return !duk_is_valid_index(ctx, index) ||
          duk_is_function(ctx, index) ||
          duk_is_undefined(ctx, index);
}
    // see http://duktape.org/guide.html#modules   
    static int js_module_search(duk_context* ctx)
    {       
        JSVM* vm = JSVM::GetJSVM(ctx);
        FileSystem* fs = vm->GetSubsystem<FileSystem>();
        ResourceCache* cache = vm->GetSubsystem<ResourceCache>();

        int top = duk_get_top(ctx);

        assert(top ==  4);

        String moduleID = duk_to_string(ctx, 0);

        if (top > 1)
        {
            // require function
            assert(duk_is_function(ctx, 1));
        }
        
        if (top > 2)
        {
            // exports
            assert(duk_is_object(ctx, 2));
        }

        if (top > 3)        
        {
            // module (module.id == a resolved absolute identifier for the module being loaded)
            assert(duk_is_object(ctx, 3));
        }

        String pathName, fileName, extension;
        SplitPath(moduleID, pathName, fileName, extension);
        String path = moduleID;

        // Do we really want this?  It is nice to not have to specify the Atomic path
        if (fileName.StartsWith("Atomic"))
        {
            path = "AtomicModules/" + path + ".js";
        }
        else
        {
            path += ".js";

            if (!cache->Exists(path))
            {
                const Vector<String>& searchPaths = vm->GetModuleSearchPaths();
                for (unsigned i = 0; i < searchPaths.Size(); i++)
                {
                    String search = searchPaths[i] + path;
                    if (cache->Exists(search))
                    {
                        path = search;
                        break;
                    }
                }
            }
        }

        if (cache->Exists(path))
        {
            SharedPtr<File> jsfile(cache->GetFile(path, false));
            vm->SetLastModuleSearchFile(jsfile->GetFullPath());
            String source;
            jsfile->ReadText(source);
            source.Append('\n');
            duk_push_string(ctx, source.CString());
            return 1;
        }
        else
        {
            // we're not a JS file, so check if we're a native module
            const Vector<String>& resourceDirs = cache->GetResourceDirs();

            for (unsigned i = 0; i < resourceDirs.Size(); i++)
            {

             String pluginLibrary;

             // TODO: proper platform folder detection
#ifdef ATOMIC_PLATFORM_WINDOWS              
              pluginLibrary = resourceDirs.At(i) + "Plugins/Windows/x64/" + moduleID + ".dll";
#elif ATOMIC_PLATFORM_OSX
             pluginLibrary = resourceDirs.At(i) + "Plugins/Mac/x64/lib" + moduleID + ".dylib";
#endif

               if (pluginLibrary.Length() && fs->FileExists(pluginLibrary))
                {
                    // let duktape know we loaded a native module
                    if (jsplugin_load(vm, pluginLibrary))
                    {
                        duk_push_undefined(ctx);
                        return 1;
                    }
                    else
                    {
                        duk_push_sprintf(ctx, "Failed loading native plugins: %s", pluginLibrary.CString());
                        duk_throw(ctx);
                    }
                }
            }

        }

        duk_push_sprintf(ctx, "Failed loading module: %s", path.CString());
        duk_throw(ctx);

    }
Esempio n. 14
0
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;
}
Esempio n. 15
0
static VALUE ctx_stack_to_value(struct state *state, int index)
{
  duk_context *ctx = state->ctx;
  size_t len;
  const char *buf;
  int type;

  state->was_complex = 0;

  type = duk_get_type(ctx, index);
  switch (type) {
    case DUK_TYPE_NULL:
    case DUK_TYPE_UNDEFINED:
      return Qnil;

    case DUK_TYPE_NUMBER:
      return rb_float_new(duk_get_number(ctx, index));

    case DUK_TYPE_BOOLEAN:
      return duk_get_boolean(ctx, index) ? Qtrue : Qfalse;

    case DUK_TYPE_STRING:
      buf = duk_get_lstring(ctx, index, &len);
      VALUE str = rb_str_new(buf, len);
      return decode_cesu8(state, str);

    case DUK_TYPE_OBJECT:
      if (duk_is_function(ctx, index)) {
        state->was_complex = 1;
        return state->complex_object;
      } else if (duk_is_array(ctx, index)) {
        VALUE ary = rb_ary_new();
        duk_enum(ctx, index, DUK_ENUM_ARRAY_INDICES_ONLY);
        while (duk_next(ctx, -1, 1)) {
          rb_ary_store(ary, duk_to_int(ctx, -2), ctx_stack_to_value(state, -1));
          duk_pop_2(ctx);
        }
        duk_pop(ctx);
        return ary;
      } else if (duk_is_object(ctx, index)) {
        VALUE hash = rb_hash_new();
        duk_enum(ctx, index, DUK_ENUM_OWN_PROPERTIES_ONLY);
        while (duk_next(ctx, -1, 1)) {
          VALUE key = ctx_stack_to_value(state, -2);
          VALUE val = ctx_stack_to_value(state, -1);
          duk_pop_2(ctx);
          if (state->was_complex)
            continue;
          rb_hash_aset(hash, key, val);
        }
        duk_pop(ctx);
        return hash;
      } else {
        state->was_complex = 1;
        return state->complex_object;
      }

    case DUK_TYPE_BUFFER:
    case DUK_TYPE_POINTER:
    default:
      return state->complex_object;
  }

  return Qnil;
}
Esempio n. 16
0
void
_gum_duk_args_parse (const GumDukArgs * args,
                     const gchar * format,
                     ...)
{
  duk_context * ctx = args->ctx;
  GumDukCore * core = args->core;
  va_list ap;
  duk_idx_t arg_index;
  const gchar * t;
  gboolean is_required;
  GSList * byte_arrays = NULL;
  const gchar * error_message = NULL;

  va_start (ap, format);

  arg_index = 0;
  is_required = TRUE;
  for (t = format; *t != '\0'; t++)
  {
    if (*t == '|')
    {
      is_required = FALSE;
      continue;
    }

    if (arg_index >= duk_get_top (ctx) || duk_is_undefined (ctx, arg_index))
    {
      if (is_required)
        goto missing_argument;
      else
        break;
    }

    switch (*t)
    {
      case 'i':
      {
        if (!duk_is_number (ctx, arg_index))
          goto expected_int;

        *va_arg (ap, gint *) = duk_require_int (ctx, arg_index);

        break;
      }
      case 'u':
      {
        guint u;

        if (!_gum_duk_get_uint (ctx, arg_index, &u))
          goto expected_uint;

        *va_arg (ap, guint *) = (guint) u;

        break;
      }
      case 'q':
      {
        gint64 i;
        gboolean is_fuzzy;

        is_fuzzy = t[1] == '~';
        if (is_fuzzy)
          t++;

        if (is_fuzzy)
        {
          if (!_gum_duk_parse_int64 (ctx, arg_index, core, &i))
            goto expected_int;
        }
        else
        {
          if (!_gum_duk_get_int64 (ctx, arg_index, core, &i))
            goto expected_int;
        }

        *va_arg (ap, gint64 *) = i;

        break;
      }
      case 'Q':
      {
        guint64 u;
        gboolean is_fuzzy;

        is_fuzzy = t[1] == '~';
        if (is_fuzzy)
          t++;

        if (is_fuzzy)
        {
          if (!_gum_duk_parse_uint64 (ctx, arg_index, core, &u))
            goto expected_uint;
        }
        else
        {
          if (!_gum_duk_get_uint64 (ctx, arg_index, core, &u))
            goto expected_uint;
        }

        *va_arg (ap, guint64 *) = u;

        break;
      }
      case 'z':
      {
        gssize value;

        if (duk_is_number (ctx, arg_index))
        {
          value = (gssize) duk_require_int (ctx, arg_index);
        }
        else
        {
          duk_push_heapptr (ctx, core->int64);
          duk_push_heapptr (ctx, core->uint64);

          if (duk_instanceof (ctx, arg_index, -2))
          {
            GumDukInt64 * object;

            object = _gum_duk_require_data (ctx, arg_index);

            value = (gssize) object->value;
          }
          else if (duk_instanceof (ctx, arg_index, -1))
          {
            GumDukUInt64 * object;

            object = _gum_duk_require_data (ctx, arg_index);

            value = (gssize) object->value;
          }
          else
          {
            goto expected_int;
          }

          duk_pop_2 (ctx);
        }

        *va_arg (ap, gssize *) = value;

        break;
      }
      case 'Z':
      {
        gsize value;

        if (duk_is_number (ctx, arg_index))
        {
          duk_double_t number;

          number = duk_require_number (ctx, arg_index);
          if (number < 0)
            goto expected_uint;

          value = (gsize) number;
        }
        else
        {
          duk_push_heapptr (ctx, core->int64);
          duk_push_heapptr (ctx, core->uint64);

          if (duk_instanceof (ctx, arg_index, -1))
          {
            GumDukUInt64 * object;

            object = _gum_duk_require_data (ctx, arg_index);

            value = (gsize) object->value;
          }
          else if (duk_instanceof (ctx, arg_index, -2))
          {
            GumDukInt64 * object;

            object = _gum_duk_require_data (ctx, arg_index);
            if (object->value < 0)
              goto expected_uint;

            value = (gsize) object->value;
          }
          else
          {
            goto expected_uint;
          }

          duk_pop_2 (ctx);
        }

        *va_arg (ap, gsize *) = value;

        break;
      }
      case 'n':
      {
        if (!duk_is_number (ctx, arg_index))
          goto expected_number;

        *va_arg (ap, gdouble *) = duk_require_number (ctx, arg_index);

        break;
      }
      case 'p':
      {
        gpointer ptr;
        gboolean is_fuzzy;

        is_fuzzy = t[1] == '~';
        if (is_fuzzy)
          t++;

        if (is_fuzzy)
        {
          if (!_gum_duk_parse_pointer (ctx, arg_index, core, &ptr))
            goto expected_pointer;
        }
        else
        {
          if (!_gum_duk_get_pointer (ctx, arg_index, core, &ptr))
            goto expected_pointer;
        }

        *va_arg (ap, gpointer *) = ptr;

        break;
      }
      case 's':
      {
        const gchar * str;
        gboolean is_nullable;

        is_nullable = t[1] == '?';
        if (is_nullable)
          t++;

        if (is_nullable && duk_is_null (ctx, arg_index))
          str = NULL;
        else if ((str = duk_get_string (ctx, arg_index)) == NULL)
          goto expected_string;

        *va_arg (ap, const gchar **) = str;

        break;
      }
      case 'm':
      {
        GumPageProtection prot;

        if (!_gum_duk_parse_protection (ctx, arg_index, &prot))
          goto expected_protection;

        *va_arg (ap, GumPageProtection *) = prot;

        break;
      }
      case 'V':
      {
        GumDukHeapPtr value;

        value = duk_get_heapptr (ctx, arg_index);
        if (value == NULL)
          goto expected_heap_pointer;

        *va_arg (ap, GumDukHeapPtr *) = value;

        break;
      }
      case 'O':
      {
        if (!duk_is_object (ctx, arg_index))
          goto expected_object;

        *va_arg (ap, GumDukHeapPtr *) = duk_require_heapptr (ctx, arg_index);

        break;
      }
      case 'A':
      {
        GumDukHeapPtr array;
        gboolean is_nullable;

        is_nullable = t[1] == '?';
        if (is_nullable)
          t++;

        if (duk_is_array (ctx, arg_index))
          array = duk_require_heapptr (ctx, arg_index);
        else if (is_nullable && duk_is_null (ctx, arg_index))
          array = NULL;
        else
          goto expected_array;

        *va_arg (ap, GumDukHeapPtr *) = array;

        break;
      }
      case 'F':
      {
        GumDukHeapPtr func;
        gboolean is_expecting_object, is_nullable;

        is_expecting_object = t[1] == '{';
        if (is_expecting_object)
          t += 2;

        if (is_expecting_object)
        {
          const gchar * next, * end, * t_end;

          if (!duk_is_object (ctx, arg_index))
            goto expected_callback_object;

          do
          {
            gchar name[64];
            gsize length;

            next = strchr (t, ',');
            end = strchr (t, '}');
            t_end = (next != NULL && next < end) ? next : end;
            length = t_end - t;
            strncpy (name, t, length);

            is_nullable = name[length - 1] == '?';
            if (is_nullable)
              name[length - 1] = '\0';
            else
              name[length] = '\0';

            duk_get_prop_string (ctx, arg_index, name);
            if (duk_is_function (ctx, -1))
            {
              func = duk_require_heapptr (ctx, -1);
            }
            else if (is_nullable && duk_is_null_or_undefined (ctx, -1))
            {
              func = NULL;
            }
            else
            {
              duk_pop (ctx);
              goto expected_callback_value;
            }
            duk_pop (ctx);

            *va_arg (ap, GumDukHeapPtr *) = func;

            t = t_end + 1;
          }
          while (t_end != end);

          t--;
        }
        else
        {
          is_nullable = t[1] == '?';
          if (is_nullable)
            t++;

          if (duk_is_function (ctx, arg_index))
            func = duk_require_heapptr (ctx, arg_index);
          else if (is_nullable && duk_is_null (ctx, arg_index))
            func = NULL;
          else
            goto expected_function;

          *va_arg (ap, GumDukHeapPtr *) = func;
        }

        break;
      }
      case 'B':
      {
        GBytes * bytes;
        gboolean is_nullable;

        is_nullable = t[1] == '?';
        if (is_nullable)
          t++;

        if (is_nullable && duk_is_null (ctx, arg_index))
          bytes = NULL;
        else if (!_gum_duk_parse_bytes (ctx, arg_index, &bytes))
          goto expected_bytes;

        *va_arg (ap, GBytes **) = bytes;

        if (bytes != NULL)
          byte_arrays = g_slist_prepend (byte_arrays, bytes);

        break;
      }
      case 'C':
      {
        GumCpuContext * cpu_context;
        gboolean is_nullable;

        is_nullable = t[1] == '?';
        if (is_nullable)
          t++;

        if (is_nullable && duk_is_null (ctx, arg_index))
          cpu_context = NULL;
        else if ((cpu_context = _gum_duk_get_cpu_context (ctx, arg_index,
            core)) == NULL)
          goto expected_cpu_context;

        *va_arg (ap, GumCpuContext **) = cpu_context;

        break;
      }
      default:
        g_assert_not_reached ();
    }

    arg_index++;
  }

  va_end (ap);

  g_slist_free (byte_arrays);

  return;

missing_argument:
  {
    error_message = "missing argument";
    goto error;
  }
expected_int:
  {
    error_message = "expected an integer";
    goto error;
  }
expected_uint:
  {
    error_message = "expected an unsigned integer";
    goto error;
  }
expected_number:
  {
    error_message = "expected a number";
    goto error;
  }
expected_pointer:
  {
    error_message = "expected a pointer";
    goto error;
  }
expected_string:
  {
    error_message = "expected a string";
    goto error;
  }
expected_protection:
  {
    error_message = "expected a string specifying memory protection";
    goto error;
  }
expected_heap_pointer:
  {
    error_message = "expected a heap-allocated object";
    goto error;
  }
expected_object:
  {
    error_message = "expected an object";
    goto error;
  }
expected_array:
  {
    error_message = "expected an array";
    goto error;
  }
expected_callback_object:
  {
    error_message = "expected an object containing callbacks";
    goto error;
  }
expected_callback_value:
  {
    error_message = "expected a callback value";
    goto error;
  }
expected_function:
  {
    error_message = "expected a function";
    goto error;
  }
expected_bytes:
  {
    error_message = "expected a buffer-like object";
    goto error;
  }
expected_cpu_context:
  {
    error_message = "expected a CpuContext object";
    goto error;
  }
error:
  {
    va_end (ap);

    g_slist_foreach (byte_arrays, (GFunc) g_bytes_unref, NULL);
    g_slist_free (byte_arrays);

    g_assert (error_message != NULL);
    _gum_duk_throw (ctx, error_message);
  }
}
void JSEventHelper::HandleEvent(StringHash eventType, VariantMap& eventData)
{
    if (object_.Null())
        return;

    JSVM* vm = JSVM::GetJSVM(0);
    duk_context* ctx = vm->GetJSContext();

    duk_idx_t top = duk_get_top(ctx);

    js_push_class_object_instance(ctx, this);

    duk_get_prop_string(ctx, -1, "__eventHelperFunctions");

    assert(duk_is_object(ctx, -1));

    duk_get_prop_string(ctx, -1, eventType.ToString().CString());

    if (duk_is_function(ctx, -1))
    {
        // look in the variant map cache
        duk_push_global_stash(ctx);
        duk_get_prop_index(ctx, -1, JS_GLOBALSTASH_VARIANTMAP_CACHE);
        duk_push_pointer(ctx, (void*) &eventData);
        duk_get_prop(ctx, -2);

        if (!duk_is_object(ctx, -1))
        {
            // pop result
            duk_pop(ctx);

            // we need to push a new variant map and store to cache
            // the cache object will be cleared at the send end in  the
            // global listener above
            js_push_variantmap(ctx, eventData);
            duk_push_pointer(ctx, (void*) &eventData);
            duk_dup(ctx, -2);
            duk_put_prop(ctx, -4);

        }

        duk_remove(ctx, -2); // vmap cache
        duk_remove(ctx, -2); // global stash

        if (duk_pcall(ctx, 1) != 0)
        {
            vm->SendJSErrorEvent();
        }
        else
        {
            // For widget events, need to check return value
            // and set whether handled
            if (eventType == E_WIDGETEVENT)
            {
                if (duk_is_boolean(ctx, -1))
                {
                    if (duk_to_boolean(ctx, -1))
                    {
                        eventData[WidgetEvent::P_HANDLED] = true;
                    }
                }
            }
        }
    }

    duk_set_top(ctx, top);

}
Esempio n. 18
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");
	}
}
Esempio n. 19
0
DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_hstring *h_input;
	duk_hstring *h_match;
	duk_hstring *h_search;
	duk_hobject *h_re;
	duk_bufwriter_ctx bw_alloc;
	duk_bufwriter_ctx *bw;
#ifdef DUK_USE_REGEXP_SUPPORT
	duk_bool_t is_regexp;
	duk_bool_t is_global;
#endif
	duk_bool_t is_repl_func;
	duk_uint32_t match_start_coff, match_start_boff;
#ifdef DUK_USE_REGEXP_SUPPORT
	duk_int_t match_caps;
#endif
	duk_uint32_t prev_match_end_boff;
	const duk_uint8_t *r_start, *r_end, *r;   /* repl string scan */
	duk_size_t tmp_sz;

	DUK_ASSERT_TOP(ctx, 2);
	h_input = duk_push_this_coercible_to_string(ctx);
	DUK_ASSERT(h_input != NULL);

	bw = &bw_alloc;
	DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input));  /* input size is good output starting point */

	DUK_ASSERT_TOP(ctx, 4);

	/* stack[0] = search value
	 * stack[1] = replace value
	 * stack[2] = input string
	 * stack[3] = result buffer
	 */

	h_re = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP);
	if (h_re) {
#ifdef DUK_USE_REGEXP_SUPPORT
		is_regexp = 1;
		is_global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);

		if (is_global) {
			/* start match from beginning */
			duk_push_int(ctx, 0);
			duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
		}
#else  /* DUK_USE_REGEXP_SUPPORT */
		return DUK_RET_UNSUPPORTED_ERROR;
#endif  /* DUK_USE_REGEXP_SUPPORT */
	} else {
		duk_to_string(ctx, 0);
#ifdef DUK_USE_REGEXP_SUPPORT
		is_regexp = 0;
		is_global = 0;
#endif
	}

	if (duk_is_function(ctx, 1)) {
		is_repl_func = 1;
		r_start = NULL;
		r_end = NULL;
	} else {
		duk_hstring *h_repl;

		is_repl_func = 0;
		h_repl = duk_to_hstring(ctx, 1);
		DUK_ASSERT(h_repl != NULL);
		r_start = DUK_HSTRING_GET_DATA(h_repl);
		r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl);
	}

	prev_match_end_boff = 0;

	for (;;) {
		/*
		 *  If matching with a regexp:
		 *    - non-global RegExp: lastIndex not touched on a match, zeroed
		 *      on a non-match
		 *    - global RegExp: on match, lastIndex will be updated by regexp
		 *      executor to point to next char after the matching part (so that
		 *      characters in the matching part are not matched again)
		 *
		 *  If matching with a string:
		 *    - always non-global match, find first occurrence
		 *
		 *  We need:
		 *    - The character offset of start-of-match for the replacer function
		 *    - The byte offsets for start-of-match and end-of-match to implement
		 *      the replacement values $&, $`, and $', and to copy non-matching
		 *      input string portions (including header and trailer) verbatim.
		 *
		 *  NOTE: the E5.1 specification is a bit vague how the RegExp should
		 *  behave in the replacement process; e.g. is matching done first for
		 *  all matches (in the global RegExp case) before any replacer calls
		 *  are made?  See: test-bi-string-proto-replace.js for discussion.
		 */

		DUK_ASSERT_TOP(ctx, 4);

#ifdef DUK_USE_REGEXP_SUPPORT
		if (is_regexp) {
			duk_dup(ctx, 0);
			duk_dup(ctx, 2);
			duk_regexp_match(thr);  /* [ ... regexp input ] -> [ res_obj ] */
			if (!duk_is_object(ctx, -1)) {
				duk_pop(ctx);
				break;
			}

			duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
			DUK_ASSERT(duk_is_number(ctx, -1));
			match_start_coff = duk_get_int(ctx, -1);
			duk_pop(ctx);

			duk_get_prop_index(ctx, -1, 0);
			DUK_ASSERT(duk_is_string(ctx, -1));
			h_match = duk_get_hstring(ctx, -1);
			DUK_ASSERT(h_match != NULL);
			duk_pop(ctx);  /* h_match is borrowed, remains reachable through match_obj */

			if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) {
				/* This should be equivalent to match() algorithm step 8.f.iii.2:
				 * detect an empty match and allow it, but don't allow it twice.
				 */
				duk_uint32_t last_index;

				duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
				last_index = (duk_uint32_t) duk_get_uint(ctx, -1);
				DUK_DDD(DUK_DDDPRINT("empty match, bump lastIndex: %ld -> %ld",
				                     (long) last_index, (long) (last_index + 1)));
				duk_pop(ctx);
				duk_push_int(ctx, last_index + 1);
				duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
			}

			DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_INT_MAX);  /* string limits */
			match_caps = (duk_int_t) duk_get_length(ctx, -1);
		} else {
#else  /* DUK_USE_REGEXP_SUPPORT */
		{  /* unconditionally */
#endif  /* DUK_USE_REGEXP_SUPPORT */
			const duk_uint8_t *p_start, *p_end, *p;   /* input string scan */
			const duk_uint8_t *q_start;               /* match string */
			duk_size_t q_blen;

#ifdef DUK_USE_REGEXP_SUPPORT
			DUK_ASSERT(!is_global);  /* single match always */
#endif

			p_start = DUK_HSTRING_GET_DATA(h_input);
			p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
			p = p_start;

			h_search = duk_get_hstring(ctx, 0);
			DUK_ASSERT(h_search != NULL);
			q_start = DUK_HSTRING_GET_DATA(h_search);
			q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search);

			p_end -= q_blen;  /* ensure full memcmp() fits in while */

			match_start_coff = 0;

			while (p <= p_end) {
				DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
				if (DUK_MEMCMP((void *) p, (void *) q_start, (size_t) q_blen) == 0) {
					duk_dup(ctx, 0);
					h_match = duk_get_hstring(ctx, -1);
					DUK_ASSERT(h_match != NULL);
#ifdef DUK_USE_REGEXP_SUPPORT
					match_caps = 0;
#endif
					goto found;
				}

				/* track utf-8 non-continuation bytes */
				if ((p[0] & 0xc0) != 0x80) {
					match_start_coff++;
				}
				p++;
			}

			/* not found */
			break;
		}
	 found:

		/* stack[0] = search value
		 * stack[1] = replace value
		 * stack[2] = input string
		 * stack[3] = result buffer
		 * stack[4] = regexp match OR match string
		 */

		match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);

		tmp_sz = (duk_size_t) (match_start_boff - prev_match_end_boff);
		DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);

		prev_match_end_boff = match_start_boff + DUK_HSTRING_GET_BYTELEN(h_match);

		if (is_repl_func) {
			duk_idx_t idx_args;
			duk_hstring *h_repl;

			/* regexp res_obj is at index 4 */

			duk_dup(ctx, 1);
			idx_args = duk_get_top(ctx);

#ifdef DUK_USE_REGEXP_SUPPORT
			if (is_regexp) {
				duk_int_t idx;
				duk_require_stack(ctx, match_caps + 2);
				for (idx = 0; idx < match_caps; idx++) {
					/* match followed by capture(s) */
					duk_get_prop_index(ctx, 4, idx);
				}
			} else {
#else  /* DUK_USE_REGEXP_SUPPORT */
			{  /* unconditionally */
#endif  /* DUK_USE_REGEXP_SUPPORT */
				/* match == search string, by definition */
				duk_dup(ctx, 0);
			}
			duk_push_int(ctx, match_start_coff);
			duk_dup(ctx, 2);

			/* [ ... replacer match [captures] match_char_offset input ] */

			duk_call(ctx, duk_get_top(ctx) - idx_args);
			h_repl = duk_to_hstring(ctx, -1);  /* -> [ ... repl_value ] */
			DUK_ASSERT(h_repl != NULL);

			DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_repl);

			duk_pop(ctx);  /* repl_value */
		} else {
			r = r_start;

			while (r < r_end) {
				duk_int_t ch1;
				duk_int_t ch2;
#ifdef DUK_USE_REGEXP_SUPPORT
				duk_int_t ch3;
#endif
				duk_size_t left;

				ch1 = *r++;
				if (ch1 != DUK_ASC_DOLLAR) {
					goto repl_write;
				}
				left = r_end - r;

				if (left <= 0) {
					goto repl_write;
				}

				ch2 = r[0];
				switch ((int) ch2) {
				case DUK_ASC_DOLLAR: {
					ch1 = (1 << 8) + DUK_ASC_DOLLAR;
					goto repl_write;
				}
				case DUK_ASC_AMP: {
					DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_match);
					r++;
					continue;
				}
				case DUK_ASC_GRAVE: {
					tmp_sz = (duk_size_t) match_start_boff;
					DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input), tmp_sz);
					r++;
					continue;
				}
				case DUK_ASC_SINGLEQUOTE: {
					duk_uint32_t match_end_boff;

					/* Use match charlen instead of bytelen, just in case the input and
					 * match codepoint encodings would have different lengths.
					 */
					match_end_boff = duk_heap_strcache_offset_char2byte(thr,
					                                                    h_input,
					                                                    match_start_coff + DUK_HSTRING_GET_CHARLEN(h_match));

					tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff);
					DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz);
					r++;
					continue;
				}
				default: {
#ifdef DUK_USE_REGEXP_SUPPORT
					duk_int_t capnum, captmp, capadv;
					/* XXX: optional check, match_caps is zero if no regexp,
					 * so dollar will be interpreted literally anyway.
					 */

					if (!is_regexp) {
						goto repl_write;
					}

					if (!(ch2 >= DUK_ASC_0 && ch2 <= DUK_ASC_9)) {
						goto repl_write;
					}
					capnum = ch2 - DUK_ASC_0;
					capadv = 1;

					if (left >= 2) {
						ch3 = r[1];
						if (ch3 >= DUK_ASC_0 && ch3 <= DUK_ASC_9) {
							captmp = capnum * 10 + (ch3 - DUK_ASC_0);
							if (captmp < match_caps) {
								capnum = captmp;
								capadv = 2;
							}
						}
					}

					if (capnum > 0 && capnum < match_caps) {
						DUK_ASSERT(is_regexp != 0);  /* match_caps == 0 without regexps */

						/* regexp res_obj is at offset 4 */
						duk_get_prop_index(ctx, 4, (duk_uarridx_t) capnum);
						if (duk_is_string(ctx, -1)) {
							duk_hstring *h_tmp_str;

							h_tmp_str = duk_get_hstring(ctx, -1);
							DUK_ASSERT(h_tmp_str != NULL);

							DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_tmp_str);
						} else {
							/* undefined -> skip (replaced with empty) */
						}
						duk_pop(ctx);
						r += capadv;
						continue;
					} else {
						goto repl_write;
					}
#else  /* DUK_USE_REGEXP_SUPPORT */
					goto repl_write;  /* unconditionally */
#endif  /* DUK_USE_REGEXP_SUPPORT */
				}  /* default case */
				}  /* switch (ch2) */

			 repl_write:
				/* ch1 = (r_increment << 8) + byte */

				DUK_BW_WRITE_ENSURE_U8(thr, bw, (duk_uint8_t) (ch1 & 0xff));
				r += ch1 >> 8;
			}  /* while repl */
		}  /* if (is_repl_func) */

		duk_pop(ctx);  /* pop regexp res_obj or match string */

#ifdef DUK_USE_REGEXP_SUPPORT
		if (!is_global) {
#else
		{  /* unconditionally; is_global==0 */
#endif
			break;
		}
	}

	/* trailer */
	tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff);
	DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);

	DUK_ASSERT_TOP(ctx, 4);
	DUK_BW_COMPACT(thr, bw);
	duk_to_string(ctx, -1);
	return 1;
}

/*
 *  split()
 */

/* XXX: very messy now, but works; clean up, remove unused variables (nomimally
 * used so compiler doesn't complain).
 */

DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_hstring *h_input;
	duk_hstring *h_sep;
	duk_uint32_t limit;
	duk_uint32_t arr_idx;
#ifdef DUK_USE_REGEXP_SUPPORT
	duk_bool_t is_regexp;
#endif
	duk_bool_t matched;  /* set to 1 if any match exists (needed for empty input special case) */
	duk_uint32_t prev_match_end_coff, prev_match_end_boff;
	duk_uint32_t match_start_boff, match_start_coff;
	duk_uint32_t match_end_boff, match_end_coff;

	DUK_UNREF(thr);

	h_input = duk_push_this_coercible_to_string(ctx);
	DUK_ASSERT(h_input != NULL);

	duk_push_array(ctx);

	if (duk_is_undefined(ctx, 1)) {
		limit = 0xffffffffUL;
	} else {
		limit = duk_to_uint32(ctx, 1);
	}

	if (limit == 0) {
		return 1;
	}

	/* If the separator is a RegExp, make a "clone" of it.  The specification
	 * algorithm calls [[Match]] directly for specific indices; we emulate this
	 * by tweaking lastIndex and using a "force global" variant of duk_regexp_match()
	 * which will use global-style matching even when the RegExp itself is non-global.
	 */

	if (duk_is_undefined(ctx, 0)) {
		/* The spec algorithm first does "R = ToString(separator)" before checking
		 * whether separator is undefined.  Since this is side effect free, we can
		 * skip the ToString() here.
		 */
		duk_dup(ctx, 2);
		duk_put_prop_index(ctx, 3, 0);
		return 1;
	} else if (duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) {
#ifdef DUK_USE_REGEXP_SUPPORT
		duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
		duk_dup(ctx, 0);
		duk_new(ctx, 1);  /* [ ... RegExp val ] -> [ ... res ] */
		duk_replace(ctx, 0);
		/* lastIndex is initialized to zero by new RegExp() */
		is_regexp = 1;
#else
		return DUK_RET_UNSUPPORTED_ERROR;
#endif
	} else {
		duk_to_string(ctx, 0);
#ifdef DUK_USE_REGEXP_SUPPORT
		is_regexp = 0;
#endif
	}

	/* stack[0] = separator (string or regexp)
	 * stack[1] = limit
	 * stack[2] = input string
	 * stack[3] = result array
	 */

	prev_match_end_boff = 0;
	prev_match_end_coff = 0;
	arr_idx = 0;
	matched = 0;

	for (;;) {
		/*
		 *  The specification uses RegExp [[Match]] to attempt match at specific
		 *  offsets.  We don't have such a primitive, so we use an actual RegExp
		 *  and tweak lastIndex.  Since the RegExp may be non-global, we use a
		 *  special variant which forces global-like behavior for matching.
		 */

		DUK_ASSERT_TOP(ctx, 4);

#ifdef DUK_USE_REGEXP_SUPPORT
		if (is_regexp) {
			duk_dup(ctx, 0);
			duk_dup(ctx, 2);
			duk_regexp_match_force_global(thr);  /* [ ... regexp input ] -> [ res_obj ] */
			if (!duk_is_object(ctx, -1)) {
				duk_pop(ctx);
				break;
			}
			matched = 1;

			duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
			DUK_ASSERT(duk_is_number(ctx, -1));
			match_start_coff = duk_get_int(ctx, -1);
			match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
			duk_pop(ctx);

			if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) {
				/* don't allow an empty match at the end of the string */
				duk_pop(ctx);
				break;
			}

			duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
			DUK_ASSERT(duk_is_number(ctx, -1));
			match_end_coff = duk_get_int(ctx, -1);
			match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff);
			duk_pop(ctx);

			/* empty match -> bump and continue */
			if (prev_match_end_boff == match_end_boff) {
				duk_push_int(ctx, match_end_coff + 1);
				duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
				duk_pop(ctx);
				continue;
			}
		} else {
#else  /* DUK_USE_REGEXP_SUPPORT */
		{  /* unconditionally */
#endif  /* DUK_USE_REGEXP_SUPPORT */
			const duk_uint8_t *p_start, *p_end, *p;   /* input string scan */
			const duk_uint8_t *q_start;               /* match string */
			duk_size_t q_blen, q_clen;

			p_start = DUK_HSTRING_GET_DATA(h_input);
			p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
			p = p_start + prev_match_end_boff;

			h_sep = duk_get_hstring(ctx, 0);
			DUK_ASSERT(h_sep != NULL);
			q_start = DUK_HSTRING_GET_DATA(h_sep);
			q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep);
			q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep);

			p_end -= q_blen;  /* ensure full memcmp() fits in while */

			match_start_coff = prev_match_end_coff;

			if (q_blen == 0) {
				/* Handle empty separator case: it will always match, and always
				 * triggers the check in step 13.c.iii initially.  Note that we
				 * must skip to either end of string or start of first codepoint,
				 * skipping over any continuation bytes!
				 *
				 * Don't allow an empty string to match at the end of the input.
				 */

				matched = 1;  /* empty separator can always match */

				match_start_coff++;
				p++;
				while (p < p_end) {
					if ((p[0] & 0xc0) != 0x80) {
						goto found;
					}
					p++;
				}
				goto not_found;
			}

			DUK_ASSERT(q_blen > 0 && q_clen > 0);
			while (p <= p_end) {
				DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
				DUK_ASSERT(q_blen > 0);  /* no issues with empty memcmp() */
				if (DUK_MEMCMP((void *) p, (void *) q_start, (duk_size_t) q_blen) == 0) {
					/* never an empty match, so step 13.c.iii can't be triggered */
					goto found;
				}

				/* track utf-8 non-continuation bytes */
				if ((p[0] & 0xc0) != 0x80) {
					match_start_coff++;
				}
				p++;
			}

		 not_found:
			/* not found */
			break;

		 found:
			matched = 1;
			match_start_boff = (duk_uint32_t) (p - p_start);
			match_end_coff = (duk_uint32_t) (match_start_coff + q_clen);  /* constrained by string length */
			match_end_boff = (duk_uint32_t) (match_start_boff + q_blen);  /* ditto */

			/* empty match (may happen with empty separator) -> bump and continue */
			if (prev_match_end_boff == match_end_boff) {
				prev_match_end_boff++;
				prev_match_end_coff++;
				continue;
			}
		}  /* if (is_regexp) */

		/* stack[0] = separator (string or regexp)
		 * stack[1] = limit
		 * stack[2] = input string
		 * stack[3] = result array
		 * stack[4] = regexp res_obj (if is_regexp)
		 */

		DUK_DDD(DUK_DDDPRINT("split; match_start b=%ld,c=%ld, match_end b=%ld,c=%ld, prev_end b=%ld,c=%ld",
		                     (long) match_start_boff, (long) match_start_coff,
		                     (long) match_end_boff, (long) match_end_coff,
		                     (long) prev_match_end_boff, (long) prev_match_end_coff));

		duk_push_lstring(ctx,
		                 (const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff),
		                 (duk_size_t) (match_start_boff - prev_match_end_boff));
		duk_put_prop_index(ctx, 3, arr_idx);
		arr_idx++;
		if (arr_idx >= limit) {
			goto hit_limit;
		}

#ifdef DUK_USE_REGEXP_SUPPORT
		if (is_regexp) {
			duk_size_t i, len;

			len = duk_get_length(ctx, 4);
			for (i = 1; i < len; i++) {
				DUK_ASSERT(i <= DUK_UARRIDX_MAX);  /* cannot have >4G captures */
				duk_get_prop_index(ctx, 4, (duk_uarridx_t) i);
				duk_put_prop_index(ctx, 3, arr_idx);
				arr_idx++;
				if (arr_idx >= limit) {
					goto hit_limit;
				}
			}

			duk_pop(ctx);
			/* lastIndex already set up for next match */
		} else {
#else  /* DUK_USE_REGEXP_SUPPORT */
		{  /* unconditionally */
#endif  /* DUK_USE_REGEXP_SUPPORT */
			/* no action */
		}

		prev_match_end_boff = match_end_boff;
		prev_match_end_coff = match_end_coff;
		continue;
	}  /* for */

	/* Combined step 11 (empty string special case) and 14-15. */

	DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld",
	                     (long) prev_match_end_boff, (long) prev_match_end_coff));

	if (DUK_HSTRING_GET_CHARLEN(h_input) > 0 || !matched) {
		/* Add trailer if:
		 *   a) non-empty input
		 *   b) empty input and no (zero size) match found (step 11)
		 */

		duk_push_lstring(ctx,
		                 (const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff,
		                 (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff));
		duk_put_prop_index(ctx, 3, arr_idx);
		/* No arr_idx update or limit check */
	}

	return 1;

 hit_limit:
#ifdef DUK_USE_REGEXP_SUPPORT
	if (is_regexp) {
		duk_pop(ctx);
	}
#endif

	return 1;
}

/*
 *  Various
 */

#ifdef DUK_USE_REGEXP_SUPPORT
DUK_LOCAL void duk__to_regexp_helper(duk_context *ctx, duk_idx_t index, duk_bool_t force_new) {
	duk_hobject *h;

	/* Shared helper for match() steps 3-4, search() steps 3-4. */

	DUK_ASSERT(index >= 0);

	if (force_new) {
		goto do_new;
	}

	h = duk_get_hobject_with_class(ctx, index, DUK_HOBJECT_CLASS_REGEXP);
	if (!h) {
		goto do_new;
	}
	return;

 do_new:
	duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
	duk_dup(ctx, index);
	duk_new(ctx, 1);  /* [ ... RegExp val ] -> [ ... res ] */
	duk_replace(ctx, index);
}
#endif  /* DUK_USE_REGEXP_SUPPORT */

#ifdef DUK_USE_REGEXP_SUPPORT
DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
	duk_hthread *thr = (duk_hthread *) ctx;

	/* Easiest way to implement the search required by the specification
	 * is to do a RegExp test() with lastIndex forced to zero.  To avoid
	 * side effects on the argument, "clone" the RegExp if a RegExp was
	 * given as input.
	 *
	 * The global flag of the RegExp should be ignored; setting lastIndex
	 * to zero (which happens when "cloning" the RegExp) should have an
	 * equivalent effect.
	 */

	DUK_ASSERT_TOP(ctx, 1);
	(void) duk_push_this_coercible_to_string(ctx);  /* at index 1 */
	duk__to_regexp_helper(ctx, 0 /*index*/, 1 /*force_new*/);

	/* stack[0] = regexp
	 * stack[1] = string
	 */

	/* Avoid using RegExp.prototype methods, as they're writable and
	 * configurable and may have been changed.
	 */

	duk_dup(ctx, 0);
	duk_dup(ctx, 1);  /* [ ... re_obj input ] */
	duk_regexp_match(thr);  /* -> [ ... res_obj ] */

	if (!duk_is_object(ctx, -1)) {
		duk_push_int(ctx, -1);
		return 1;
	}

	duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
	DUK_ASSERT(duk_is_number(ctx, -1));
	return 1;
}
#else  /* DUK_USE_REGEXP_SUPPORT */
DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
	DUK_UNREF(ctx);
	return DUK_RET_UNSUPPORTED_ERROR;
}
//duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t index);
duk_bool_t aperl_duk_is_function(duk_context *ctx, duk_idx_t index) {
	duk_bool_t ret = duk_is_function(ctx, index);
	return ret;
}
Esempio n. 21
0
static AJ_Status HandleMessage(duk_context* ctx, duk_idx_t ajIdx, AJ_Message* msg)
{
    duk_idx_t msgIdx;
    uint8_t accessor = AJS_NOT_ACCESSOR;
    const char* func;
    AJ_Status status;
    uint8_t ldstate;

#if !defined(AJS_CONSOLE_LOCKDOWN)
    status = AJS_GetLockdownState(&ldstate);
    if (status == AJ_OK && ldstate == AJS_CONSOLE_UNLOCKED) {
        status = AJS_ConsoleMsgHandler(ctx, msg);
        if (status != AJ_ERR_NO_MATCH) {
            if (status != AJ_OK) {
                AJ_WarnPrintf(("AJS_ConsoleMsgHandler returned %s\n", AJ_StatusText(status)));
            }
            return status;
        }
    }
#endif
    /*
     * JOIN_SESSION replies are handled in the AllJoyn.js layer and don't get passed to JavaScript
     */
    if (msg->msgId == AJ_REPLY_ID(AJ_METHOD_JOIN_SESSION)) {
        return AJS_HandleJoinSessionReply(ctx, msg);
    }
    /*
     * Nothing more to do if the AllJoyn module was not loaded
     */
    if (ajIdx < 0) {
        return AJ_OK;
    }
    /*
     * Let the bases services layer take a look at the message
     */
    status = AJS_ServicesMsgHandler(msg);
    if (status != AJ_ERR_NO_MATCH) {
        if (status != AJ_OK) {
            AJ_WarnPrintf(("AJS_ServicesMsgHandler returned %s\n", AJ_StatusText(status)));
        }
        return status;
    }
    /*
     * Push the appropriate callback function onto the duktape stack
     */
    if (msg->hdr->msgType == AJ_MSG_SIGNAL) {
        /*
         * About announcements and found name signal get special handling
         */
        if (msg->msgId == AJ_SIGNAL_ABOUT_ANNOUNCE) {
            return AJS_AboutAnnouncement(ctx, msg);
        }
        if (msg->msgId == AJ_SIGNAL_FOUND_ADV_NAME) {
            return AJS_FoundAdvertisedName(ctx, msg);
        }
        if ((msg->msgId == AJ_SIGNAL_SESSION_LOST) || (msg->msgId == AJ_SIGNAL_SESSION_LOST_WITH_REASON)) {
            if (AJS_DebuggerIsAttached()) {
                msg = AJS_CloneAndCloseMessage(ctx, msg);
            }
            return AJS_SessionLost(ctx, msg);
        }
        func = "onSignal";
        duk_get_prop_string(ctx, ajIdx, func);
    } else if (msg->hdr->msgType == AJ_MSG_METHOD_CALL) {
        accessor = IsPropAccessor(msg);
        switch (accessor) {
        case AJS_NOT_ACCESSOR:
            func = "onMethodCall";
            break;

        case AJ_PROP_GET:
            func = "onPropGet";
            break;

        case AJ_PROP_SET:
            func = "onPropSet";
            break;

        case AJ_PROP_GET_ALL:
            func = "onPropGetAll";
            break;

        default:
            return AJ_ERR_INVALID;
        }
        duk_get_prop_string(ctx, ajIdx, func);
    } else {
        func = "onReply";
        AJS_GetGlobalStashObject(ctx, func);
        if (duk_is_object(ctx, -1)) {
            duk_get_prop_index(ctx, -1, msg->replySerial);
            duk_swap_top(ctx, -2);
            /*
             * Clear the onReply entry
             */
            duk_del_prop_index(ctx, -1, msg->replySerial);
            duk_pop(ctx);
        }
    }
    /*
     * Skip if there is no function to call.
     */
    if (!duk_is_function(ctx, -1)) {
        if (msg->hdr->msgType == AJ_MSG_METHOD_CALL) {
            AJ_Message error;
            AJ_WarnPrintf(("%s: not registered - rejecting message\n", func));
            AJ_MarshalErrorMsg(msg, &error, AJ_ErrRejected);
            status = AJ_DeliverMsg(&error);
        } else {
            AJ_WarnPrintf(("%s: not registered - ignoring message\n", func));
            status = AJ_OK;
        }
        duk_pop(ctx);
        return status;
    }
    /*
     * Opens up a stack entry above the function
     */
    duk_dup_top(ctx);
    msgIdx = AJS_UnmarshalMessage(ctx, msg, accessor);
    AJ_ASSERT(msgIdx == (ajIdx + 3));
    /*
     * Save the message object on the stack
     */
    duk_copy(ctx, msgIdx, -3);
    /*
     * Special case for GET prop so we can get the signature for marshalling the result
     */
    if (accessor == AJS_NOT_ACCESSOR) {
        status = AJS_UnmarshalMsgArgs(ctx, msg);
    } else {
        status = AJS_UnmarshalPropArgs(ctx, msg, accessor, msgIdx);
    }
    if (status == AJ_OK) {
        duk_idx_t numArgs = duk_get_top(ctx) - msgIdx - 1;
        /*
         * If attached, the debugger will begin to unmarshal a message when the
         * method handler is called, therefore it must be cloned-and-closed now.
         */
        if (AJS_DebuggerIsAttached()) {
            msg = AJS_CloneAndCloseMessage(ctx, msg);
        }
        if (duk_pcall_method(ctx, numArgs) != DUK_EXEC_SUCCESS) {
            const char* err = duk_safe_to_string(ctx, -1);

            AJ_ErrPrintf(("%s: %s\n", func, err));
            /*
             * Generate an error reply if this was a method call
             */
            if (msg->hdr->msgType == AJ_MSG_METHOD_CALL) {
                duk_push_c_lightfunc(ctx, AJS_MethodCallError, 1, 0, 0);
                duk_insert(ctx, -3);
                (void)duk_pcall_method(ctx, 1);
            }
        }
    }
    /*
     * Cleanup stack back to the AJ object
     */
    duk_set_top(ctx, ajIdx + 1);
    return status;
}
Esempio n. 22
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;
}