diff --git a/.gitignore b/.gitignore index fd9c310..6c455bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.o *.so *.d +*_blob.bin +*_blob.h \ No newline at end of file diff --git a/Makefile b/Makefile index 57c5fbb..db7e45a 100644 --- a/Makefile +++ b/Makefile @@ -99,7 +99,8 @@ LINKER_DEPENDENCIES = -lphpcpp -lv8 RM = rm -f CP = cp -f -MKDIR = mkdir -p +MKDIR = mkdir -p +XXD = xxd -i # @@ -112,7 +113,7 @@ MKDIR = mkdir -p SOURCES = $(wildcard *.cpp) OBJECTS = $(SOURCES:%.cpp=%.o) -DEPENDENCIES = $(SOURCES:%.cpp=%.d) +DEPENDENCIES = $(SOURCES:%.cpp=%.d) # @@ -126,10 +127,20 @@ all: ${OBJECTS} ${EXTENSION} # -include ${DEPENDENCIES} +natives_blob.h: natives_blob.bin + ${CP} natives_blob.bin /tmp/natives_blob.bin + ${XXD} /tmp/natives_blob.bin > natives_blob.h + ${RM} /tmp/natives_blob.bin + +snapshot_blob.h: snapshot_blob.bin + ${CP} snapshot_blob.bin /tmp/snapshot_blob.bin + ${XXD} /tmp/snapshot_blob.bin > snapshot_blob.h + ${RM} /tmp/snapshot_blob.bin + ${EXTENSION}: ${OBJECTS} ${LINKER} ${LINKER_FLAGS} -o $@ ${OBJECTS} ${LINKER_DEPENDENCIES} -${OBJECTS}: +${OBJECTS}: snapshot_blob.h natives_blob.h ${COMPILER} ${COMPILER_FLAGS} -o $@ ${@:%.o=%.cpp} install: diff --git a/isolate.cpp b/isolate.cpp index 9d2a08f..5d45b7c 100644 --- a/isolate.cpp +++ b/isolate.cpp @@ -21,6 +21,7 @@ #include "isolate.h" #include #include +#include /** * Start namespace @@ -33,6 +34,24 @@ namespace JS { */ static thread_local std::unique_ptr isolate; +class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { +public: + virtual void* Allocate(size_t length) { + void* data = AllocateUninitialized(length); + return data == NULL ? data : memset(data, 0, length); + } + virtual void* AllocateUninitialized(size_t length) + { + return malloc(length); + } + virtual void Free(void* data, size_t) + { + free(data); + } +}; + +static ArrayBufferAllocator allocator; + /** * Constructor */ @@ -41,8 +60,14 @@ Isolate::Isolate() // create a platform Platform::create(); + // create our parameters + v8::Isolate::CreateParams params; + + // set our custom allocator + params.array_buffer_allocator = &allocator; + // create the actual isolate - _isolate = v8::Isolate::New(); + _isolate = v8::Isolate::New(params); // and enter it _isolate->Enter(); diff --git a/jsobject.cpp b/jsobject.cpp index 99659e6..431f8ed 100644 --- a/jsobject.cpp +++ b/jsobject.cpp @@ -26,6 +26,7 @@ namespace JS { */ JSObject::Iterator::Iterator(Php::Base *base, const Stack &object) : Php::Iterator(base), + _object(object), _position(0) { // create a handle scope, so variables "fall out of scope" and "enter" the context @@ -35,7 +36,6 @@ JSObject::Iterator::Iterator(Php::Base *base, const Stack &object) : // assign variables, this would normally be done inside // the initializer list, but that way we can't create a // HandleScope first and v8 refuses to work without one - _object = object; _keys = _object->GetPropertyNames(); _size = _keys->Length(); } @@ -172,7 +172,7 @@ Php::Value JSObject::__call(const char *name, Php::Parameters ¶ms) // create a handle scope, so variables "fall out of scope", "enter" the context and retrieve the value v8::HandleScope scope(Isolate::get()); v8::Context::Scope context(_object->CreationContext()); - v8::Local function(_object->Get(value(name)).As()); + v8::Local function(_object->Get(value(Php::Value(name))).As()); std::vector> input; // check whether the value actually exists diff --git a/platform.cpp b/platform.cpp index 78d2b73..b0193d9 100644 --- a/platform.cpp +++ b/platform.cpp @@ -34,6 +34,60 @@ static std::mutex mutex; */ static std::atomic platform; +/** + * Execute a v8::Task with a bit of delay, like we want in the CallDelayedOnForegroundThread + * method. + */ +class DelayedTask : public v8::Task +{ +private: + /** + * The underlying task we want to execute + * @var v8::Task + */ + v8::Task *_task; + + /** + * The amount of delay that we want before executing the task + * @var double + */ + double _delay; + +public: + /** + * Constructor + * @param task + * @param delay + */ + DelayedTask(v8::Task *task, double delay) : _task(task), _delay(delay) {} + + /** + * Destructor, we delete the underlying task from here + */ + virtual ~DelayedTask() + { + delete _task; + } + + /** + * The abstract Run method of the v8::Task interface + */ + void Run() override + { + // so first we sleep for '_delay' seconds + std::this_thread::sleep_for(std::chrono::duration(_delay)); + + // and then we run the actual task + _task->Run(); + } +}; + +/** + * Include the dumps of the natives and snapshot blobs + */ +#include "natives_blob.h" +#include "snapshot_blob.h" + /** * Constructor */ @@ -87,6 +141,20 @@ void Platform::create() // initialize the ICU and v8 engine v8::V8::InitializeICU(); + + // create a setup a StartupData object for the natives blob + v8::StartupData natives; + natives.data = (const char*) _tmp_natives_blob_bin; + natives.raw_size = _tmp_natives_blob_bin_len; + v8::V8::SetNativesDataBlob(&natives); + + // create a setup a StartupData object for the snapshot blob + v8::StartupData snapshot; + snapshot.data = (const char*) _tmp_snapshot_blob_bin; + snapshot.raw_size = _tmp_snapshot_blob_bin_len; + v8::V8::SetSnapshotDataBlob(&snapshot); + + // initialize the platform v8::V8::InitializePlatform(result); v8::V8::Initialize(); @@ -238,6 +306,20 @@ void Platform::CallOnForegroundThread(v8::Isolate *isolate, v8::Task *task) */ } +/** + * Schedules a task to be invoked on a foreground thread wrt a specific + * |isolate| after the given number of seconds |delay_in_seconds|. + * Tasks posted for the same isolate should be execute in order of + * scheduling. The definition of "foreground" is opaque to V8. + */ +void Platform::CallDelayedOnForegroundThread(v8::Isolate *isolate, v8::Task *task, double delay_in_seconds) +{ + // we simply call the CallOnBackgroundThread method which will queue our task, but before that + // we turn it into a DelayedTask. The ExpectedRuntime here doesn't matter as our implementation + // of CallOnBackgroundThread doesn't do anything with it anyway + CallOnBackgroundThread(new DelayedTask(task, delay_in_seconds), ExpectedRuntime::kShortRunningTask); +} + /** * Retrieve the monotonically increasing time. The starting point * is not relevant, but it must return at least millisecond-precision diff --git a/platform.h b/platform.h index ea33dfb..503c0aa 100644 --- a/platform.h +++ b/platform.h @@ -114,6 +114,14 @@ class Platform : public v8::Platform */ void CallOnForegroundThread(v8::Isolate *isolate, v8::Task *task) override; + /** + * Schedules a task to be invoked on a foreground thread wrt a specific + * |isolate| after the given number of seconds |delay_in_seconds|. + * Tasks posted for the same isolate should be execute in order of + * scheduling. The definition of "foreground" is opaque to V8. + */ + void CallDelayedOnForegroundThread(v8::Isolate *isolate, v8::Task *task, double delay_in_seconds) override; + /** * Retrieve the monotonically increasing time. The starting point * is not relevant, but it must return at least millisecond-precision