Beispiel #1
0
	static bool js_object_external_function_callback(
				const jerry_api_object_t *function_object_ptr,
				const jerry_api_value_t *this_object_ptr,
				jerry_api_value_t *result_value_ptr,
				const jerry_api_value_t js_api_arguments[],
				const jerry_api_length_t argumentCount) {

		const auto position = JSObject::js_object_external_functions_map__.find(function_object_ptr);
		assert(position != JSObject::js_object_external_functions_map__.end());

		auto callback = position->second;

		// TODO: Use current context
		JSContextGroup js_context_group;
		const auto js_context = js_context_group.CreateContext();
		auto function_object = JSObject(js_context, function_object_ptr);
		auto this_object     = JSObject(js_context, *this_object_ptr);
		const auto arguments = detail::to_vector(js_context, js_api_arguments, argumentCount);

		auto callback_result = callback(function_object, this_object, arguments);
		auto callback_result_value = static_cast<jerry_api_value_t>(callback_result);

		// callback value should be considered "unmanaged" from Daisy
		callback_result.unmanaged();

		detail::js_jerry_api_value_make_copy(callback_result_value, result_value_ptr);

		return true;
	}
Beispiel #2
0
  Thread* Thread::join(STATE, Object* timeout) {
    if(!vm()) return nil<Thread>();

    Thread* self = this;
    OnStack<2> os(state, self, timeout);

    state->vm()->become_unmanaged();

    {
      utilities::thread::Mutex::LockGuard guard(self->join_lock_);
      state->vm()->become_managed();
      atomic::memory_barrier();

      if(self->alive()->true_p()) {
        UnmanagedPhase unmanaged(state);

        if(timeout->nil_p()) {
          self->join_cond_.wait(self->join_lock_);
        } else {
          struct timespec ts = {0,0};
          self->join_cond_.offset(&ts, as<Float>(timeout)->value());

          if(self->join_cond_.wait_until(self->join_lock_, &ts)
                == utilities::thread::cTimedOut) {
            return nil<Thread>();
          }
        }
      }
    }

    return self;
  }
Beispiel #3
0
  void Fiber::suspend_and_continue(STATE) {
    UnmanagedPhase unmanaged(state);

    {
      std::unique_lock<std::mutex> lk(vm()->fiber_wait_mutex());

      vm()->set_suspended();
      while(!wakeup_p()) {
        vm()->fiber_wait_condition().wait(lk);
      }
      clear_wakeup();
      vm()->set_resuming();
    }

    {
      std::lock_guard<std::mutex> guard(state->vm()->thread()->fiber_mutex());

      vm()->set_running();

      while(!restart_context()->suspended_p()) {
        ; // spin wait
      }

      state->vm()->thread()->current_fiber(state, this);
    }
  }
Beispiel #4
0
  void Fiber::restart(STATE) {
    UnmanagedPhase unmanaged(state);

    {
      std::lock_guard<std::mutex> guard(state->vm()->thread()->fiber_mutex());

      if(!vm()->suspended_p()) {
        std::ostringstream msg;
        msg << "attempt to restart non-suspended ("
          << vm()->fiber_transition_flag() << ") fiber";
        Exception::raise_fiber_error(state, msg.str().c_str());
      }

      state->vm()->set_suspending();

      restart_context(state->vm());
      wakeup();

      while(vm()->suspended_p()) {
        std::lock_guard<std::mutex> guard(vm()->fiber_wait_mutex());
        vm()->fiber_wait_condition().notify_one();
      }
    }

    while(!vm()->running_p()) {
      ; // spin wait
    }
  }
Beispiel #5
0
    void FinalizerThread::extension_finalizer(STATE, Object* obj, FinalizerFunction func) {
      if(finishing_) return;

      UnmanagedPhase unmanaged(state);
      std::lock_guard<std::mutex> guard(list_mutex());

      add_finalizer(state, new ExtensionFinalizer(state, obj, func));
    }
Beispiel #6
0
    void FinalizerThread::wakeup(STATE) {
      MachineThread::wakeup(state);

      while(thread_running_p()) {
        UnmanagedPhase unmanaged(state);
        std::lock_guard<std::mutex> guard(list_mutex());

        list_condition().notify_one();
      }
    }
Beispiel #7
0
    void Response::run(STATE) {
      size_t pending_requests = 0;
      char* request = NULL;

      Channel* inbox = inbox_.get();
      Channel* outbox = outbox_.get();

      String* response = 0;
      OnStack<3> os(state, inbox, outbox, response);

      while(!thread_exit_) {
        {
          utilities::thread::SpinLock::LockGuard guard(list_lock_);

          if(request_list_->size() > 0) {
            request = request_list_->back();
            request_list_->pop_back();
          }
        }

        if(thread_exit_) break;

        if(request) {
          ManagedPhase managed(state);

          pending_requests++;

          inbox->send(state, String::create(state, request));

          request = NULL;
        }

        if(pending_requests > 0) {
          if((response = try_as<String>(outbox->try_receive(state)))) {
            write_response(state,
                reinterpret_cast<const char*>(response->byte_address()),
                response->byte_size());
            pending_requests--;
            continue;
          }
        }

        {
          UnmanagedPhase unmanaged(state);
          utilities::thread::Mutex::LockGuard guard(response_lock_);

          if(thread_exit_) break;

          response_cond_.wait(response_lock_);
        }
      }
    }
Beispiel #8
0
  void LLVMState::compile(STATE, CompiledCode* code,
      Class* receiver_class, BlockEnvironment* block_env, bool is_block)
  {
    if(!enabled_) return;

    // TODO: Fix compile policy checks
    if(!code->keywords()->nil_p()) {
      vm()->metrics().jit.methods_failed++;

      return;
    }

    // In case the method hasn't been internalized yet
    if(!code->machine_code()) {
      code->internalize(state);
    }

    JITCompileRequest* req = JITCompileRequest::create(state, code, receiver_class,
        0, block_env, is_block);

    wait_mutex.lock();
    req->waiter(&wait_cond);

    add(state, req);

    {
      UnmanagedPhase unmanaged(state);

      wait_cond.wait(wait_mutex);
    }

    wait_mutex.unlock();

    if(state->shared().config.jit_show_compiling) {
      llvm::outs() << "[[[ JIT compiled "
        << enclosure_name(code) << "#" << symbol_debug_str(code->name())
        << (req->is_block() ? " (block) " : " (method) ") << " ]]]\n";
    }
  }
Beispiel #9
0
  Object* IO::recv_fd(STATE) {
#ifdef _WIN32
    return Primitives::failure();
#else
    struct msghdr msg;
    struct iovec vec[1];
    char buf[1];

    struct cmsghdr *cmsg;
    char cmsg_buf[cmsg_space];

    msg.msg_name = NULL;
    msg.msg_namelen = 0;

    /* Linux and Solaris doesn't work if msg_iov is NULL. */
    buf[0] = '\0';
    vec[0].iov_base = buf;
    vec[0].iov_len = 1;
    msg.msg_iov = vec;
    msg.msg_iovlen = 1;

    msg.msg_control = (caddr_t)cmsg_buf;
    msg.msg_controllen = sizeof(cmsg_buf);
    msg.msg_flags = 0;
    cmsg = CMSG_FIRSTHDR(&msg);
    memset(cmsg_buf, 0, sizeof(cmsg_buf));
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;

    // Workaround for GCC's broken strict-aliasing checks.
    int* fd_data = (int *)CMSG_DATA(cmsg);
    *fd_data = -1;

    int read_fd = descriptor(state);

    int code = -1;

  retry:
    state->vm()->interrupt_with_signal();
    state->vm()->thread()->sleep(state, cTrue);

    {
      UnmanagedPhase unmanaged(state);
      code = recvmsg(read_fd, &msg, 0);
    }

    state->vm()->thread()->sleep(state, cFalse);
    state->vm()->clear_waiter();

    if(code == -1) {
      if(errno == EAGAIN || errno == EINTR) {
        if(state->vm()->thread_interrupted_p(state)) return NULL;
        ensure_open(state);
        goto retry;
      }

      return Primitives::failure();
    }

    if(msg.msg_controllen != CMSG_SPACE(sizeof(int))
        || cmsg->cmsg_len != CMSG_LEN(sizeof(int))
        || cmsg->cmsg_level != SOL_SOCKET
        || cmsg->cmsg_type != SCM_RIGHTS) {
      return Primitives::failure();
    }

    // Workaround for GCC's broken strict-aliasing checks.
    fd_data = (int *)CMSG_DATA(cmsg);
    return Fixnum::from(*fd_data);
#endif
  }
Beispiel #10
0
  Object* IO::socket_read(STATE, Fixnum* bytes, Fixnum* flags, Fixnum* type) {
    char buf[1024];
    socklen_t alen = sizeof(buf);
    size_t size = (size_t)bytes->to_native();

    String* buffer = String::create_pinned(state, bytes);

    OnStack<1> variables(state, buffer);

    ssize_t bytes_read;
    native_int t = type->to_native();

  retry:
    state->vm()->interrupt_with_signal();
    state->vm()->thread()->sleep(state, cTrue);

    {
      UnmanagedPhase unmanaged(state);

      bytes_read = recvfrom(descriptor(state),
                            (char*)buffer->byte_address(), size,
                            flags->to_native(),
                            (struct sockaddr*)buf, &alen);
    }

    state->vm()->thread()->sleep(state, cFalse);
    state->vm()->clear_waiter();

    buffer->unpin();

    if(bytes_read == -1) {
      if(errno == EINTR) {
        if(state->vm()->thread_interrupted_p(state)) return NULL;
        ensure_open(state);
        goto retry;
      } else {
        Exception::raise_errno_error(state, "read(2) failed");
      }

      return NULL;
    }

    buffer->num_bytes(state, Fixnum::from(bytes_read));

    if(t == 0) return buffer; // none

    Array* ary = Array::create(state, 2);
    ary->set(state, 0, buffer);

    switch(type->to_native()) {
    case 1: // ip
      // Hack from MRI:
      // OSX doesn't return a 'from' result from recvfrom for connection-oriented sockets
      if(alen && alen != sizeof(buf)) {
        ary->set(state, 1, ipaddr(state, (struct sockaddr*)buf, alen));
      } else {
        ary->set(state, 1, cNil);
      }
      break;
#ifndef RBX_WINDOWS
    case 2: // unix
      ary->set(state, 1, unixaddr(state, (struct sockaddr_un*)buf, alen));
      break;
#endif
    default:
      ary->set(state, 1, String::create(state, buf, alen));
    }

    return ary;
  }
Beispiel #11
0
void Session::logout( String* reason )
{ QF_STACK_TRY
  unmanaged().logout( convertString(reason) );
  QF_STACK_CATCH
}
Beispiel #12
0
void Session::logout()
{ QF_STACK_TRY
  unmanaged().logout();
  QF_STACK_CATCH
}
Beispiel #13
0
  void LLVMState::compile_soon(STATE, CompiledCode* code,
                               Class* receiver_class, BlockEnvironment* block_env, bool is_block)
  {
    bool wait = config().jit_sync;

    if(!enabled_) return;

    // TODO: Fix compile policy checks
    if(!code->keywords()->nil_p()) {
      vm()->metrics().jit.methods_failed++;

      return;
    }

    if(code->machine_code()->call_count <= 1) {
      return;
    }

    if(code->machine_code()->compiling_p()) {
      return;
    }

    int hits = code->machine_code()->method_call_count();
    code->machine_code()->set_compiling();

    JITCompileRequest* req = JITCompileRequest::create(state, code, receiver_class,
        hits, block_env, is_block);

    if(wait) {
      wait_mutex.lock();

      req->waiter(&wait_cond);

      add(state, req);
      bool req_block = req->is_block();

      {
        UnmanagedPhase unmanaged(state);

        wait_cond.wait(wait_mutex);
      }

      wait_mutex.unlock();

      if(state->shared().config.jit_show_compiling) {
        llvm::outs() << "[[[ JIT compiled "
          << enclosure_name(code) << "#" << symbol_debug_str(code->name())
          << (req_block ? " (block) " : " (method) ")
          << " (" << hits << ") " << " ]]]\n";
      }
    } else {
      add(state, req);

      if(state->shared().config.jit_show_compiling) {
        llvm::outs() << "[[[ JIT queued "
          << enclosure_name(code) << "#" << symbol_debug_str(code->name())
          << (req->is_block() ? " (block) " : " (method) ")
          << " (" << hits << ") " << " ]]]\n";
      }
    }
  }
Beispiel #14
0
  void LLVMState::run(STATE) {
    state_ = state;

    JITCompileRequest* compile_request = nil<JITCompileRequest>();
    OnStack<1> os(state, compile_request);

    state->vm()->become_managed();

    bool show_machine_code_ = jit_dump_code() & cMachineCode;

    while(!thread_exit_) {

      current_compiler_ = 0;

      {
        UnmanagedPhase unmanaged(state);

        {
          utilities::thread::Mutex::LockGuard lg(compile_lock_);

          while(compile_list_.get()->empty_p()) {
            compile_cond_.wait(compile_lock_);

            if(thread_exit_) break;
          }
        }
      }

      if(thread_exit_) break;

      {
        utilities::thread::Mutex::LockGuard guard(request_lock_);

        compile_request = try_as<JITCompileRequest>(compile_list_.get()->shift(state));
        if(!compile_request || compile_request->nil_p()) continue;
      }

      utilities::thread::Condition* cond = compile_request->waiter();

      // Don't proceed until requester has reached the wait_cond
      if(cond) wait_mutex.lock();

      Context ctx(this);
      jit::Compiler jit(&ctx);

      current_compiler_ = &jit;

      uint32_t class_id = 0;
      uint32_t serial_id = 0;
      void* func = 0;

      try {
        if(compile_request->receiver_class() &&
            !compile_request->receiver_class()->nil_p()) {
          // Apparently already compiled, probably some race
          if(compile_request->method()->find_specialized(
                compile_request->receiver_class())) {
            if(config().jit_show_compiling) {
              CompiledCode* code = compile_request->method();
              llvm::outs() << "[[[ JIT already compiled "
                        << enclosure_name(code) << "#" << symbol_debug_str(code->name())
                        << (compile_request->is_block() ? " (block)" : " (method)")
                        << " ]]]\n";
            }

            // If someone was waiting on this, wake them up.
            if(cond) {
              wait_mutex.unlock();
              cond->signal();
            }

            current_compiler_ = 0;

            continue;
          }

          class_id = compile_request->receiver_class()->class_id();
          serial_id = compile_request->receiver_class()->serial_id();
        }

        {
          timer::StopWatch<timer::microseconds> timer(
              vm()->metrics().jit.compile_time_us);

          jit.compile(compile_request);

          bool indy = !config().jit_sync;
          func = jit.generate_function(indy);
        }

        // We were unable to compile this function, likely
        // because it's got something we don't support.
        if(!func) {
          if(config().jit_show_compiling) {
            CompiledCode* code = compile_request->method();
            llvm::outs() << "[[[ JIT error background compiling "
                      << enclosure_name(code) << "#" << symbol_debug_str(code->name())
                      << (compile_request->is_block() ? " (block)" : " (method)")
                      << " ]]]\n";
          }
          // If someone was waiting on this, wake them up.
          if(cond) {
            wait_mutex.unlock();
            cond->signal();
          }

          current_compiler_ = 0;

          continue;
        }
      } catch(LLVMState::CompileError& e) {
        logger::info("JIT: compile error: %s", e.error());

        vm()->metrics().jit.methods_failed++;

        // If someone was waiting on this, wake them up.
        if(cond) {
          wait_mutex.unlock();
          cond->signal();
        }
        current_compiler_ = 0;

        continue;
      }

      if(show_machine_code_) {
        jit.show_machine_code();
      }

      // If the method has had jit'ing request disabled since we started
      // JIT'ing it, discard our work.
      if(!compile_request->machine_code()->jit_disabled()) {

        jit::RuntimeDataHolder* rd = ctx.runtime_data_holder();

        atomic::memory_barrier();
        start_method_update();

        if(!compile_request->is_block()) {
          if(class_id) {
            compile_request->method()->add_specialized(state,
                class_id, serial_id, reinterpret_cast<executor>(func), rd);
          } else {
            compile_request->method()->set_unspecialized(reinterpret_cast<executor>(func), rd);
          }
        } else {
          compile_request->method()->set_unspecialized(reinterpret_cast<executor>(func), rd);
        }

        compile_request->machine_code()->clear_compiling();

        end_method_update();

        rd->run_write_barrier(shared().om, compile_request->method());

        if(config().jit_show_compiling) {
          CompiledCode* code = compile_request->method();
          llvm::outs() << "[[[ JIT finished background compiling "
                    << enclosure_name(code) << "#" << symbol_debug_str(code->name())
                    << (compile_request->is_block() ? " (block)" : " (method)")
                    << " ]]]\n";
        }
      }

      // If someone was waiting on this, wake them up.
      if(cond) {
        wait_mutex.unlock();
        cond->signal();
      }

      current_compiler_ = 0;
      vm()->metrics().jit.methods_compiled++;
    }
  }