├── README.md ├── src ├── utils │ ├── getTimer.h │ ├── File.h │ ├── File.cpp │ └── getTimer.cpp ├── core │ ├── NativeTest.h │ ├── Rectangle.h │ ├── Rectangle.cpp │ ├── Matrix.h │ ├── NativeTest.cpp │ └── Matrix.cpp ├── binding │ ├── V8Matrix.h │ ├── V8Console.h │ ├── V8Rectangle.h │ ├── V8Console.cpp │ ├── JSHelper.h │ ├── V8Rectangle.cpp │ └── V8Matrix.cpp ├── debug │ ├── Log.cpp │ ├── Log.h │ ├── Socket.h │ ├── DebugAgent.h │ ├── Socket.cpp │ └── DebugAgent.cpp ├── Main.cpp └── js │ └── JSTest.js ├── .gitignore ├── LICENSE └── CMakeLists.txt /README.md: -------------------------------------------------------------------------------- 1 | # V8Performace 2 | V8中JS调用C++各种方式的性能对比。 3 | 4 | 测试结果参考:[V8中JS与C++性能测试对比](http://www.idom.me/articles/845.html) 5 | -------------------------------------------------------------------------------- /src/utils/getTimer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef V8PERFORMANCE_GETTIMER_H 3 | #define V8PERFORMANCE_GETTIMER_H 4 | 5 | double getTimer(); 6 | 7 | 8 | #endif //V8PERFORMANCE_GETTIMER_H 9 | -------------------------------------------------------------------------------- /src/core/NativeTest.h: -------------------------------------------------------------------------------- 1 | #ifndef V8PERFORMANCE_NATIVETEST_H 2 | #define V8PERFORMANCE_NATIVETEST_H 3 | 4 | 5 | void runNative(const short* data, const int TIMES, const int SIZE); 6 | 7 | #endif //V8PERFORMANCE_NATIVETEST_H 8 | -------------------------------------------------------------------------------- /src/utils/File.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef V8PERFORMANCE_FILE_H 3 | #define V8PERFORMANCE_FILE_H 4 | 5 | #include 6 | 7 | class File { 8 | public: 9 | static std::string read(const char* fileName); 10 | }; 11 | 12 | 13 | #endif //V8PERFORMANCE_FILE_H 14 | -------------------------------------------------------------------------------- /src/utils/File.cpp: -------------------------------------------------------------------------------- 1 | #include "File.h" 2 | #include 3 | 4 | std::string File::read(const char* fileName) { 5 | std::ifstream t(fileName); 6 | std::string str((std::istreambuf_iterator(t)), 7 | std::istreambuf_iterator()); 8 | return str; 9 | } -------------------------------------------------------------------------------- /src/binding/V8Matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef V8PERFORMANCE_V8MATRIX_H 2 | #define V8PERFORMANCE_V8MATRIX_H 3 | 4 | #include "v8.h" 5 | 6 | class V8Matrix { 7 | public: 8 | static void install(v8::Isolate* isolate, v8::Local parent); 9 | }; 10 | 11 | 12 | #endif //V8PERFORMANCE_V8MATRIX_H 13 | -------------------------------------------------------------------------------- /src/binding/V8Console.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef V8PERFORMANCE_V8CONSOLE_H 3 | #define V8PERFORMANCE_V8CONSOLE_H 4 | 5 | #include "v8.h" 6 | 7 | class V8Console { 8 | public: 9 | static void install(v8::Isolate* isolate, v8::Local parent); 10 | }; 11 | 12 | 13 | #endif //V8PERFORMANCE_V8CONSOLE_H 14 | -------------------------------------------------------------------------------- /src/binding/V8Rectangle.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef V8PERFORMANCE_V8RECTANGLE_H 3 | #define V8PERFORMANCE_V8RECTANGLE_H 4 | 5 | #include "v8.h" 6 | 7 | class V8Rectangle { 8 | public: 9 | static void install(v8::Isolate* isolate, v8::Local parent); 10 | }; 11 | 12 | 13 | #endif //V8PERFORMANCE_V8RECTANGLE_H 14 | -------------------------------------------------------------------------------- /src/utils/getTimer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "getTimer.h" 3 | #include 4 | 5 | /** 6 | * 返回自1970年1月1日 00:00:00 UTC到当前时间的毫秒数 7 | */ 8 | double getTimer() { 9 | auto now = std::chrono::high_resolution_clock::now(); 10 | std::chrono::duration ns = now.time_since_epoch(); 11 | return ns.count(); 12 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | /third_party/ 30 | -------------------------------------------------------------------------------- /src/core/Rectangle.h: -------------------------------------------------------------------------------- 1 | #ifndef V8PERFORMANCE_RECTANGLE_H 2 | #define V8PERFORMANCE_RECTANGLE_H 3 | 4 | #include "string" 5 | 6 | class Rectangle { 7 | public: 8 | Rectangle(float x = 0, float y = 0, float width = 0, float height = 0); 9 | 10 | void setTo(float x, float y, float width, float height); 11 | 12 | std::string toString(); 13 | 14 | float x, y, width, height; 15 | }; 16 | 17 | 18 | #endif //V8PERFORMANCE_RECTANGLE_H 19 | -------------------------------------------------------------------------------- /src/debug/Log.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Log.h" 3 | #include 4 | #include 5 | 6 | void printLog(const char format[], ...) { 7 | va_list args; 8 | va_start(args, format); 9 | vfprintf(stdout, format, args); 10 | va_end(args); 11 | fprintf(stdout, "\n"); 12 | } 13 | 14 | void printError(const char format[], ...) { 15 | va_list args; 16 | va_start(args, format); 17 | vfprintf(stderr, format, args); 18 | va_end(args); 19 | fprintf(stderr, "\n"); 20 | } -------------------------------------------------------------------------------- /src/core/Rectangle.cpp: -------------------------------------------------------------------------------- 1 | #include "Rectangle.h" 2 | 3 | Rectangle::Rectangle(float x, float y, float width, float height) { 4 | this->setTo(x, y, width, height); 5 | } 6 | 7 | void Rectangle::setTo(float x, float y, float width, float height) { 8 | this->x = x; 9 | this->y = y; 10 | this->width = width; 11 | this->height = height; 12 | } 13 | 14 | std::string Rectangle::toString() { 15 | return "(x=" + std::to_string(this->x) + ", y=" + std::to_string(this->y) + 16 | ", width=" + std::to_string(this->width) + ", height=" + std::to_string(this->height) + ")"; 17 | } -------------------------------------------------------------------------------- /src/debug/Log.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef V8PERFORMANCE_LOG_H 3 | #define V8PERFORMANCE_LOG_H 4 | 5 | #include 6 | 7 | #if !defined(V8PERFORMANCE_DEBUG) && !defined(V8PERFORMANCE_RELEASE) 8 | #ifdef NDEBUG 9 | #define V8PERFORMANCE_RELEASE 10 | #else 11 | #define V8PERFORMANCE_DEBUG 12 | #endif 13 | #endif 14 | 15 | 16 | void printLog(const char format[], ...); 17 | void printError(const char format[], ...); 18 | 19 | #ifdef V8PERFORMANCE_DEBUG 20 | 21 | #define LOG(...) printLog(__VA_ARGS__) 22 | #define ASSERT(assertion) \ 23 | if(!(assertion)) { \ 24 | do { \ 25 | printError("%s:%d: fatal error: \"%s\"\n", __FILE__, __LINE__, #assertion); \ 26 | abort(); \ 27 | } while (false); \ 28 | } 29 | #else 30 | 31 | #define LOG(...) 32 | #define ASSERT(assertion) 33 | 34 | #endif 35 | 36 | #endif //V8PERFORMANCE_LOG_H 37 | -------------------------------------------------------------------------------- /src/core/Matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef V8PERFORMANCE_MATRIX_H 2 | #define V8PERFORMANCE_MATRIX_H 3 | 4 | #include "string" 5 | #include "Rectangle.h" 6 | 7 | class Matrix { 8 | public: 9 | static void transformBoundsNoField(float x, float y, float width, float height); 10 | 11 | Matrix(float a = 1, float b = 0, float c = 0, float d = 1, float tx = 0, float ty = 0); 12 | 13 | /** 14 | * 将 Matrix 的成员设置为指定值 15 | * @param a 缩放或旋转图像时影响像素沿 x 轴定位的值。 16 | * @param b 旋转或倾斜图像时影响像素沿 y 轴定位的值。 17 | * @param c 旋转或倾斜图像时影响像素沿 x 轴定位的值。 18 | * @param d 缩放或旋转图像时影响像素沿 y 轴定位的值。 19 | * @param tx 沿 x 轴平移每个点的距离。 20 | * @param ty 沿 y 轴平移每个点的距离。 21 | */ 22 | void setTo(float a, float b, float c, float d, float tx, float ty); 23 | 24 | void transformBounds(Rectangle* bounds); 25 | 26 | std::string toString(); 27 | 28 | float a, b, c, d, tx, ty; 29 | }; 30 | 31 | 32 | #endif //V8PERFORMANCE_MATRIX_H 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Dom Chen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/binding/V8Console.cpp: -------------------------------------------------------------------------------- 1 | #include "V8Console.h" 2 | #include "../core/NativeTest.h" 3 | #include "JSHelper.h" 4 | 5 | namespace { 6 | 7 | void logMethod(const v8::FunctionCallbackInfo& args) { 8 | v8::String::Utf8Value utf8(args[0]); 9 | printf("%s\n", *utf8); 10 | } 11 | 12 | void runtNativeTestMethod(const v8::FunctionCallbackInfo& args) { 13 | auto isolate = args.GetIsolate(); 14 | auto context = isolate->GetCurrentContext(); 15 | auto times = static_cast(args[1]->NumberValue(context).FromJust()); 16 | auto array = v8::Local::Cast(args[0]); 17 | int size = int(array->Length() / 4); 18 | auto content = array->Buffer()->GetContents(); 19 | auto data = (short*) content.Data(); 20 | runNative(data, times, size); 21 | } 22 | } 23 | 24 | void V8Console::install(v8::Isolate* isolate, v8::Local parent) { 25 | auto console = v8::ObjectTemplate::New(isolate); 26 | console->Set(isolate, "log", v8::FunctionTemplate::New(isolate, logMethod)); 27 | parent->Set(isolate, "runtNativeTest", 28 | v8::FunctionTemplate::New(isolate, runtNativeTestMethod)); 29 | parent->Set(isolate, "console", console); 30 | } -------------------------------------------------------------------------------- /src/debug/Socket.h: -------------------------------------------------------------------------------- 1 | #ifndef V8PERFORMANCE_SOCKET_H 2 | #define V8PERFORMANCE_SOCKET_H 3 | 4 | #include "Log.h" 5 | 6 | class Socket final { 7 | public: 8 | Socket(); 9 | 10 | ~Socket(); 11 | 12 | // Server initialization. 13 | bool bind(int port); 14 | bool listen(int backlog); 15 | Socket* accept(); 16 | 17 | /** 18 | * Client initialization. 19 | */ 20 | bool connect(const char* host, const char* port); 21 | 22 | /** 23 | * Shutdown socket for both read and write. This causes blocking send and receive calls to exit. 24 | * After |shutdown()| the Socket object cannot be used for any communication. 25 | */ 26 | bool shutdown(); 27 | 28 | // Data Transmission 29 | // Return 0 on failure. 30 | int send(const char* buffer, int length); 31 | int receive(char* buffer, int length); 32 | 33 | /** 34 | * Set the value of the SO_REUSEADDR socket option. 35 | */ 36 | bool setReuseAddress(bool reuse_address); 37 | 38 | bool isValid() const; 39 | 40 | static int getLastError(); 41 | 42 | 43 | private: 44 | class PlatformData; 45 | 46 | PlatformData* data; 47 | 48 | explicit Socket(PlatformData* data) : data(data) {} 49 | }; 50 | 51 | 52 | #endif // V8PERFORMANCE_SOCKET_H 53 | -------------------------------------------------------------------------------- /src/core/NativeTest.cpp: -------------------------------------------------------------------------------- 1 | #include "NativeTest.h" 2 | #include "Matrix.h" 3 | #include "Rectangle.h" 4 | #include "../utils/getTimer.h" 5 | #include "iostream" 6 | 7 | 8 | void runNative(const short* data, const int TIMES, const int SIZE) { 9 | 10 | auto rect = new Rectangle(); 11 | auto matrix = new Matrix(2, 0, 0, 0.5, 11, 19); 12 | //Native测试 13 | auto start = getTimer(); 14 | for (int t = 0; t < TIMES; t++) { 15 | int index = 0; 16 | for (int i = 0; i < SIZE; i++) { 17 | short x = data[index++]; 18 | short y = data[index++]; 19 | short width = data[index++]; 20 | short height = data[index++]; 21 | rect->setTo(x, y, width, height); 22 | matrix->transformBounds(rect); 23 | } 24 | } 25 | auto nativeTime = getTimer() - start; 26 | std::cout << "Native耗时:" << (int) nativeTime << "ms\n"; 27 | 28 | //Native-NoField测试 29 | start = getTimer(); 30 | for (int t = 0; t < TIMES; t++) { 31 | int index = 0; 32 | for (int i = 0; i < SIZE; i++) { 33 | short x = data[index++]; 34 | short y = data[index++]; 35 | short width = data[index++]; 36 | short height = data[index++]; 37 | Matrix::transformBoundsNoField(x, y, width, height); 38 | } 39 | } 40 | auto nativeNoPropTime = getTimer() - start; 41 | std::cout << "Native-NoField耗时:" << (int) nativeTime << "ms\n"; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/binding/JSHelper.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef V8PERFORMANCE_JSHELPER_H 3 | #define V8PERFORMANCE_JSHELPER_H 4 | 5 | #include 6 | 7 | 8 | #define JSString(text) v8::String::NewFromUtf8(isolate, text, v8::NewStringType::kNormal).ToLocalChecked() 9 | #define JSFunction(callback) v8::Function::New(context,callback).ToLocalChecked() 10 | 11 | #define GETTER_ARGUMENT v8::Local property, const v8::PropertyCallbackInfo& info 12 | 13 | #define GETTER_CONTENT(className, name) \ 14 | auto self = info.Holder(); \ 15 | auto ptr = self->GetAlignedPointerFromInternalField(0); \ 16 | auto value = static_cast(ptr)->name; \ 17 | info.GetReturnValue().Set(value); 18 | 19 | #define SETTER_ARGUMENT v8::Local property, v8::Local value, const v8::PropertyCallbackInfo& info 20 | 21 | #define SETTER_CONTENT(className, name) \ 22 | auto self = info.Holder(); \ 23 | auto isolate = info.GetIsolate(); \ 24 | auto context = isolate->GetCurrentContext(); \ 25 | auto ptr = self->GetAlignedPointerFromInternalField(0); \ 26 | static_cast(ptr)->name = (float) value->NumberValue(context).FromJust(); 27 | 28 | #define SET_ACCESSOR(name, getter, setter) self->SetAccessor(context, JSString(name), getter, setter); 29 | 30 | #define SET_METHOD(name, method) prototypeTemplate->Set(isolate, name, \ 31 | v8::FunctionTemplate::New(isolate, method)); 32 | 33 | 34 | #endif //V8PERFORMANCE_JSHELPER_H 35 | -------------------------------------------------------------------------------- /src/debug/DebugAgent.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef V8PERFORMANCE_DEBUGAGENT_H 3 | #define V8PERFORMANCE_DEBUGAGENT_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include "Socket.h" 9 | 10 | /** 11 | * Debug agent which starts a socket listener on the debugger port and handles connection from a remote debugger. 12 | */ 13 | class DebugAgent { 14 | public: 15 | 16 | /** 17 | * Enable the V8 debug agent. The debug agent will listen on the supplied TCP/IP port for remote debugger connection. 18 | * @param hostName the name of the embedding application. 19 | * @param port the TCP/IP port to listen on. 20 | * @param waitForConnection whether V8 should pause on a first statement allowing remote debugger to connect before 21 | * anything interesting happened. 22 | */ 23 | static void Enable(const std::string& hostName, int port, bool waitForConnection = false); 24 | /** 25 | * Disable the V8 debug agent. The TCP/IP connection will be closed. 26 | */ 27 | static void Disable(); 28 | 29 | private: 30 | static DebugAgent* debugAgent; 31 | static bool initialized; 32 | 33 | DebugAgent(v8::Isolate* isolate, const std::string& hostName, int port, bool waitForConnection); 34 | ~DebugAgent(); 35 | void runClientLoop(); 36 | void onDebugMessage(const v8::Debug::Message& message); 37 | 38 | bool terminate; 39 | v8::Isolate* isolate; 40 | std::string hostName; 41 | int port; // Port to use for the agent. 42 | Socket* server; // Server socket for listen/accept. 43 | Socket* client; // Client socket for send/receive. 44 | 45 | std::thread thread; 46 | 47 | friend class DebugAgentSession; 48 | 49 | friend void DebugAgentMessageHandler(const v8::Debug::Message& message); 50 | }; 51 | 52 | #endif //V8PERFORMANCE_DEBUGAGENT_H 53 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(V8Performance) 3 | set (CMAKE_CXX_STANDARD 11) 4 | set(CMAKE_CXX_FLAGS "-stdlib=libc++ ") 5 | set(CMAKE_OSX_DEPLOYMENT_TARGET 10.7) 6 | file (GLOB_RECURSE SOURCE_FILES src/*.cpp src/*.h) 7 | 8 | if (CMAKE_BUILD_TYPE STREQUAL Release) 9 | set(BUILD_TYPE darwin-x64-release) 10 | else () 11 | set(BUILD_TYPE darwin-x64-debug) 12 | endif () 13 | 14 | function (find_include_dirs out) 15 | file (GLOB_RECURSE headers ${ARGN}) 16 | foreach (path ${headers}) 17 | get_filename_component (dir ${path} PATH) 18 | list (APPEND include_dirs ${dir}) 19 | endforeach() 20 | list (REMOVE_DUPLICATES include_dirs) 21 | set (${out} ${include_dirs} PARENT_SCOPE) 22 | endfunction() 23 | 24 | find_include_dirs(includes third_party/v8/include/*.h) 25 | include_directories(${includes} src) 26 | file (GLOB_RECURSE v8_lib third_party/v8/${BUILD_TYPE}/*.a) 27 | 28 | set(RESOURCE_FILES) 29 | 30 | function(copy_file from to) 31 | set(temp ${RESOURCE_FILES}) 32 | list(APPEND temp ${to}) 33 | set(RESOURCE_FILES ${temp} PARENT_SCOPE) 34 | add_custom_command(OUTPUT ${to} 35 | COMMAND ${CMAKE_COMMAND} -E copy ${from} ${to} 36 | MAIN_DEPENDENCY ${from}) 37 | endfunction() 38 | 39 | copy_file(${CMAKE_SOURCE_DIR}/src/js/JSTest.js ${CMAKE_BINARY_DIR}/JSTest.js) 40 | #copy natives_blob.bin and snapshot_blob.bin which v8 requires to the root of binary dir. 41 | copy_file(${CMAKE_SOURCE_DIR}/third_party/v8/${BUILD_TYPE}/natives_blob.bin ${CMAKE_BINARY_DIR}/natives_blob.bin) 42 | copy_file(${CMAKE_SOURCE_DIR}/third_party/v8/${BUILD_TYPE}/snapshot_blob.bin ${CMAKE_BINARY_DIR}/snapshot_blob.bin) 43 | 44 | add_custom_target(CopyResource ALL DEPENDS ${RESOURCE_FILES}) 45 | 46 | add_executable(Main ${SOURCE_FILES}) 47 | 48 | if (MSVC) 49 | set(cc_flags "/w /GR-") 50 | else() 51 | set(cc_flags "-w -fno-rtti -fno-exceptions") 52 | endif() 53 | set_target_properties(Main PROPERTIES 54 | COMPILE_FLAGS ${cc_flags} 55 | CXX_VISIBILITY_PRESET hidden 56 | VISIBILITY_INLINES_HIDDEN true) 57 | 58 | target_link_libraries(Main ${v8_lib}) -------------------------------------------------------------------------------- /src/binding/V8Rectangle.cpp: -------------------------------------------------------------------------------- 1 | #include "V8Rectangle.h" 2 | #include "../core/Rectangle.h" 3 | #include "JSHelper.h" 4 | 5 | namespace { 6 | 7 | void xGetter(GETTER_ARGUMENT) { GETTER_CONTENT(Rectangle, x); } 8 | 9 | void xSetter(SETTER_ARGUMENT) { SETTER_CONTENT(Rectangle, x); } 10 | 11 | void yGetter(GETTER_ARGUMENT) { GETTER_CONTENT(Rectangle, y); } 12 | 13 | void ySetter(SETTER_ARGUMENT) { SETTER_CONTENT(Rectangle, y); } 14 | 15 | void widthGetter(GETTER_ARGUMENT) { GETTER_CONTENT(Rectangle, width); } 16 | 17 | void widthSetter(SETTER_ARGUMENT) { SETTER_CONTENT(Rectangle, width); } 18 | 19 | void heightGetter(GETTER_ARGUMENT) { GETTER_CONTENT(Rectangle, height); } 20 | 21 | void heightSetter(SETTER_ARGUMENT) { SETTER_CONTENT(Rectangle, height); } 22 | 23 | 24 | void setToMethod(const v8::FunctionCallbackInfo& args) { 25 | auto isolate = args.GetIsolate(); 26 | auto context = isolate->GetCurrentContext(); 27 | float x = float(args[0]->IsUndefined() ? 0 : args[0]->NumberValue(context).FromJust()); 28 | float y = float(args[1]->IsUndefined() ? 0 : args[1]->NumberValue(context).FromJust()); 29 | float width = float(args[2]->IsUndefined() ? 0 : args[2]->NumberValue(context).FromJust()); 30 | float height = float(args[3]->IsUndefined() ? 0 : args[3]->NumberValue(context).FromJust()); 31 | auto self = args.Holder(); 32 | auto ptr = self->GetAlignedPointerFromInternalField(0); 33 | static_cast(ptr)->setTo(x, y, width, height); 34 | } 35 | 36 | void toStringMethod(const v8::FunctionCallbackInfo& args) { 37 | auto self = args.Holder(); 38 | auto isolate = args.GetIsolate(); 39 | auto rect = static_cast(self->GetAlignedPointerFromInternalField(0)); 40 | auto value = rect->toString(); 41 | auto utf = JSString(value.c_str()); 42 | args.GetReturnValue().Set(utf); 43 | } 44 | 45 | void constructor(const v8::FunctionCallbackInfo& args) { 46 | auto isolate = args.GetIsolate(); 47 | auto context = isolate->GetCurrentContext(); 48 | float x = float(args[0]->IsUndefined() ? 0 : args[0]->NumberValue(context).FromJust()); 49 | float y = float(args[1]->IsUndefined() ? 0 : args[1]->NumberValue(context).FromJust()); 50 | float width = float(args[2]->IsUndefined() ? 0 : args[2]->NumberValue(context).FromJust()); 51 | float height = float(args[3]->IsUndefined() ? 0 : args[3]->NumberValue(context).FromJust()); 52 | Rectangle* rect = new Rectangle(x, y, width, height); 53 | auto self = args.Holder(); 54 | self->SetAlignedPointerInInternalField(0, rect); 55 | SET_ACCESSOR("x", xGetter, xSetter); 56 | SET_ACCESSOR("y", yGetter, ySetter); 57 | SET_ACCESSOR("width", widthGetter, widthSetter); 58 | SET_ACCESSOR("height", heightGetter, heightSetter); 59 | args.GetReturnValue().Set(self); 60 | } 61 | 62 | 63 | } 64 | 65 | void V8Rectangle::install(v8::Isolate* isolate, v8::Local parent) { 66 | auto classTemplate = v8::FunctionTemplate::New(isolate, constructor); 67 | classTemplate->SetClassName(JSString("Rectangle")); 68 | auto prototypeTemplate = classTemplate->PrototypeTemplate(); 69 | SET_METHOD("setTo", setToMethod); 70 | SET_METHOD("toString", toStringMethod); 71 | classTemplate->InstanceTemplate()->SetInternalFieldCount(1); 72 | 73 | parent->Set(JSString("Rectangle"), classTemplate); 74 | } 75 | -------------------------------------------------------------------------------- /src/core/Matrix.cpp: -------------------------------------------------------------------------------- 1 | #include "Matrix.h" 2 | #include "math.h" 3 | 4 | Matrix::Matrix(float a, float b, float c, float d, float tx, float ty) { 5 | this->setTo(a, b, c, d, tx, ty); 6 | } 7 | 8 | void Matrix::setTo(float a, float b, float c, float d, float tx, float ty) { 9 | this->a = a; 10 | this->b = b; 11 | this->c = c; 12 | this->d = d; 13 | this->tx = tx; 14 | this->ty = ty; 15 | } 16 | 17 | void Matrix::transformBounds(Rectangle* bounds) { 18 | if (!bounds) { 19 | return; 20 | } 21 | auto a = this->a; 22 | auto b = this->b; 23 | auto c = this->c; 24 | auto d = this->d; 25 | auto tx = this->tx; 26 | auto ty = this->ty; 27 | 28 | auto x = bounds->x; 29 | auto y = bounds->y; 30 | auto xMax = x + bounds->width; 31 | auto yMax = y + bounds->height; 32 | 33 | auto x0 = a * x + c * y + tx; 34 | auto y0 = b * x + d * y + ty; 35 | auto x1 = a * xMax + c * y + tx; 36 | auto y1 = b * xMax + d * y + ty; 37 | auto x2 = a * xMax + c * yMax + tx; 38 | auto y2 = b * xMax + d * yMax + ty; 39 | auto x3 = a * x + c * yMax + tx; 40 | auto y3 = b * x + d * yMax + ty; 41 | 42 | float tmp = 0; 43 | 44 | if (x0 > x1) { 45 | tmp = x0; 46 | x0 = x1; 47 | x1 = tmp; 48 | } 49 | if (x2 > x3) { 50 | tmp = x2; 51 | x2 = x3; 52 | x3 = tmp; 53 | } 54 | 55 | bounds->x = floorf(x0 < x2 ? x0 : x2); 56 | bounds->width = ceilf((x1 > x3 ? x1 : x3) - bounds->x); 57 | 58 | if (y0 > y1) { 59 | tmp = y0; 60 | y0 = y1; 61 | y1 = tmp; 62 | } 63 | if (y2 > y3) { 64 | tmp = y2; 65 | y2 = y3; 66 | y3 = tmp; 67 | } 68 | 69 | bounds->y = floorf(y0 < y2 ? y0 : y2); 70 | bounds->height = ceilf((y1 > y3 ? y1 : y3) - bounds->y); 71 | } 72 | 73 | std::string Matrix::toString() { 74 | return "(a=" + std::to_string(this->a) + ", b=" + std::to_string(this->b) + ", c=" + std::to_string(this->c) + 75 | ", d=" + std::to_string(this->d) + ", tx=" + std::to_string(this->tx) + ", ty=" + std::to_string(this->ty) + 76 | ")"; 77 | } 78 | 79 | void Matrix::transformBoundsNoField(float x, float y, float width, float height) { 80 | float a = 2; 81 | float b = 0; 82 | float c = 0; 83 | float d = 0.5; 84 | float tx = 11; 85 | float ty = 19; 86 | 87 | float xMax = x + width; 88 | float yMax = y + height; 89 | 90 | float x0 = a * x + c * y + tx; 91 | float y0 = b * x + d * y + ty; 92 | float x1 = a * xMax + c * y + tx; 93 | float y1 = b * xMax + d * y + ty; 94 | float x2 = a * xMax + c * yMax + tx; 95 | float y2 = b * xMax + d * yMax + ty; 96 | float x3 = a * x + c * yMax + tx; 97 | float y3 = b * x + d * yMax + ty; 98 | 99 | float tmp = 0; 100 | 101 | if (x0 > x1) { 102 | tmp = x0; 103 | x0 = x1; 104 | x1 = tmp; 105 | } 106 | if (x2 > x3) { 107 | tmp = x2; 108 | x2 = x3; 109 | x3 = tmp; 110 | } 111 | 112 | x = floorf(x0 < x2 ? x0 : x2); 113 | width = ceilf((x1 > x3 ? x1 : x3) - x); 114 | 115 | if (y0 > y1) { 116 | tmp = y0; 117 | y0 = y1; 118 | y1 = tmp; 119 | } 120 | if (y2 > y3) { 121 | tmp = y2; 122 | y2 = y3; 123 | y3 = tmp; 124 | } 125 | 126 | y = floorf(y0 < y2 ? y0 : y2); 127 | height = ceilf((y1 > y3 ? y1 : y3) - y); 128 | } -------------------------------------------------------------------------------- /src/Main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "libplatform/libplatform.h" 6 | #include "v8.h" 7 | #include "binding/V8Console.h" 8 | #include "binding/V8Matrix.h" 9 | #include "binding/V8Rectangle.h" 10 | #include "utils/File.h" 11 | #include "debug/DebugAgent.h" 12 | 13 | using namespace v8; 14 | 15 | class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { 16 | public: 17 | virtual void* Allocate(size_t length) { 18 | void* data = AllocateUninitialized(length); 19 | return data == NULL ? data : memset(data, 0, length); 20 | } 21 | 22 | virtual void* AllocateUninitialized(size_t length) { return malloc(length); } 23 | 24 | virtual void Free(void* data, size_t) { free(data); } 25 | }; 26 | 27 | 28 | int main(int argc, char* argv[]) { 29 | // Initialize V8. 30 | V8::InitializeExternalStartupData("natives_blob.bin", "snapshot_blob.bin"); 31 | Platform* platform = platform::CreateDefaultPlatform(); 32 | V8::InitializePlatform(platform); 33 | V8::Initialize(); 34 | 35 | // Create a new Isolate and make it the current one. 36 | ArrayBufferAllocator allocator; 37 | Isolate::CreateParams create_params; 38 | create_params.array_buffer_allocator = &allocator; 39 | Isolate* isolate = Isolate::New(create_params); 40 | { 41 | Isolate::Scope isolate_scope(isolate); 42 | 43 | // Create a stack-allocated handle scope. 44 | HandleScope handle_scope(isolate); 45 | 46 | Local global = ObjectTemplate::New(isolate); 47 | V8Console::install(isolate, global); 48 | V8Rectangle::install(isolate, global); 49 | V8Matrix::install(isolate, global); 50 | 51 | // Create a new context. 52 | Local context = Context::New(isolate, nullptr, global); 53 | 54 | // Enter the context for compiling and running the hello world script. 55 | Context::Scope context_scope(context); 56 | 57 | std::string path = argv[0]; 58 | std::replace(path.begin(), path.end(), '\\', '/'); 59 | auto index = path.rfind("/"); 60 | std::string currentPath = path.substr(0, index + 1); 61 | 62 | // Enable the debug angent. 63 | std::string arg = argc > 1 ? argv[1] : ""; 64 | bool waitForConnection = (arg == "--debug-brk"); 65 | DebugAgent::Enable("Elven", 5959, waitForConnection); 66 | 67 | auto jsPath = currentPath + "JSTest.js"; 68 | auto text = File::read(jsPath.c_str()); 69 | auto source = v8::String::NewFromUtf8(isolate, text.c_str(), 70 | v8::NewStringType::kNormal).ToLocalChecked(); 71 | v8::ScriptOrigin origin( 72 | v8::String::NewFromUtf8(isolate, jsPath.c_str(), 73 | v8::NewStringType::kNormal).ToLocalChecked()); 74 | TryCatch tryCatch(isolate); 75 | auto script = v8::Script::Compile(context, source, &origin); 76 | if (script.IsEmpty()) { 77 | Local exception = tryCatch.Exception(); 78 | String::Utf8Value exception_str(exception); 79 | printf("Exception: %s\n", *exception_str); 80 | } 81 | else { 82 | // Run the script to get the result. 83 | Local result = script.ToLocalChecked()->Run(context).ToLocalChecked(); 84 | 85 | if (result.IsEmpty()) { 86 | Local exception = tryCatch.Exception(); 87 | String::Utf8Value exception_str(exception); 88 | printf("Exception: %s\n", *exception_str); 89 | } 90 | } 91 | 92 | } 93 | 94 | // Dispose the isolate and tear down V8. 95 | isolate->Dispose(); 96 | DebugAgent::Disable(); 97 | V8::Dispose(); 98 | V8::ShutdownPlatform(); 99 | delete platform; 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /src/binding/V8Matrix.cpp: -------------------------------------------------------------------------------- 1 | #include "V8Matrix.h" 2 | #include "core/Matrix.h" 3 | #include "binding/JSHelper.h" 4 | 5 | namespace { 6 | 7 | void aGetter(GETTER_ARGUMENT) { GETTER_CONTENT(Matrix, a); } 8 | 9 | void aSetter(SETTER_ARGUMENT) { SETTER_CONTENT(Matrix, a); } 10 | 11 | void bGetter(GETTER_ARGUMENT) { GETTER_CONTENT(Matrix, b); } 12 | 13 | void bSetter(SETTER_ARGUMENT) { SETTER_CONTENT(Matrix, b); } 14 | 15 | void cGetter(GETTER_ARGUMENT) { GETTER_CONTENT(Matrix, c); } 16 | 17 | void cSetter(SETTER_ARGUMENT) { SETTER_CONTENT(Matrix, c); } 18 | 19 | void dGetter(GETTER_ARGUMENT) { GETTER_CONTENT(Matrix, d); } 20 | 21 | void dSetter(SETTER_ARGUMENT) { SETTER_CONTENT(Matrix, d); } 22 | 23 | void txGetter(GETTER_ARGUMENT) { GETTER_CONTENT(Matrix, tx); } 24 | 25 | void txSetter(SETTER_ARGUMENT) { SETTER_CONTENT(Matrix, tx); } 26 | 27 | void tyGetter(GETTER_ARGUMENT) { GETTER_CONTENT(Matrix, ty); } 28 | 29 | void tySetter(SETTER_ARGUMENT) { SETTER_CONTENT(Matrix, ty); } 30 | 31 | void setToMethod(const v8::FunctionCallbackInfo& args) { 32 | auto isolate = args.GetIsolate(); 33 | auto context = isolate->GetCurrentContext(); 34 | float a = float(args[0]->IsUndefined() ? 1 : args[0]->NumberValue(context).FromJust()); 35 | float b = float(args[1]->IsUndefined() ? 0 : args[1]->NumberValue(context).FromJust()); 36 | float c = float(args[2]->IsUndefined() ? 0 : args[2]->NumberValue(context).FromJust()); 37 | float d = float(args[3]->IsUndefined() ? 1 : args[3]->NumberValue(context).FromJust()); 38 | float tx = float(args[4]->IsUndefined() ? 0 : args[4]->NumberValue(context).FromJust()); 39 | float ty = float(args[5]->IsUndefined() ? 0 : args[5]->NumberValue(context).FromJust()); 40 | auto self = args.Holder(); 41 | auto ptr = self->GetAlignedPointerFromInternalField(0); 42 | static_cast(ptr)->setTo(a, b, c, d, tx, ty); 43 | } 44 | 45 | void transformBoundsMethod(const v8::FunctionCallbackInfo& args) { 46 | auto obj = v8::Local::Cast(args[0]); 47 | auto rect = static_cast(obj->GetAlignedPointerFromInternalField(0)); 48 | auto self = args.Holder(); 49 | auto matrix = static_cast(self->GetAlignedPointerFromInternalField(0)); 50 | matrix->transformBounds(rect); 51 | } 52 | 53 | void toStringMethod(const v8::FunctionCallbackInfo& args) { 54 | auto self = args.Holder(); 55 | auto matrix = static_cast(self->GetAlignedPointerFromInternalField(0)); 56 | auto value = matrix->toString(); 57 | auto utf = v8::String::NewFromUtf8(args.GetIsolate(), value.c_str(), 58 | v8::NewStringType::kNormal).ToLocalChecked(); 59 | args.GetReturnValue().Set(utf); 60 | } 61 | 62 | void constructor(const v8::FunctionCallbackInfo& args) { 63 | auto isolate = args.GetIsolate(); 64 | auto context = isolate->GetCurrentContext(); 65 | float a = float(args[0]->IsUndefined() ? 1 : args[0]->NumberValue(context).FromJust()); 66 | float b = float(args[1]->IsUndefined() ? 0 : args[1]->NumberValue(context).FromJust()); 67 | float c = float(args[2]->IsUndefined() ? 0 : args[2]->NumberValue(context).FromJust()); 68 | float d = float(args[3]->IsUndefined() ? 1 : args[3]->NumberValue(context).FromJust()); 69 | float tx = float(args[4]->IsUndefined() ? 0 : args[4]->NumberValue(context).FromJust()); 70 | float ty = float(args[5]->IsUndefined() ? 0 : args[5]->NumberValue(context).FromJust()); 71 | Matrix* matrix = new Matrix(a, b, c, d, tx, ty); 72 | auto self = args.Holder(); 73 | self->SetAlignedPointerInInternalField(0, matrix); 74 | SET_ACCESSOR("a", aGetter, aSetter); 75 | SET_ACCESSOR("b", bGetter, bSetter); 76 | SET_ACCESSOR("c", cGetter, cSetter); 77 | SET_ACCESSOR("d", dGetter, dSetter); 78 | SET_ACCESSOR("tx", txGetter, txSetter); 79 | SET_ACCESSOR("ty", tyGetter, tySetter); 80 | args.GetReturnValue().Set(self); 81 | } 82 | 83 | 84 | } 85 | 86 | void V8Matrix::install(v8::Isolate* isolate, v8::Local parent) { 87 | auto classTemplate = v8::FunctionTemplate::New(isolate, constructor); 88 | classTemplate->SetClassName(JSString("Matrix")); 89 | auto prototypeTemplate = classTemplate->PrototypeTemplate(); 90 | SET_METHOD("setTo", setToMethod); 91 | SET_METHOD("transformBounds", transformBoundsMethod); 92 | SET_METHOD("toString", toStringMethod); 93 | classTemplate->InstanceTemplate()->SetInternalFieldCount(1); 94 | 95 | parent->Set(isolate, "Matrix", classTemplate); 96 | } 97 | 98 | -------------------------------------------------------------------------------- /src/debug/Socket.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Socket.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static const int InvalidNativeHandle = -1; 12 | 13 | class Socket::PlatformData { 14 | public: 15 | PlatformData() { 16 | nativeHandle = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 17 | } 18 | 19 | explicit PlatformData(int nativeHandle) : nativeHandle(nativeHandle) { 20 | 21 | } 22 | 23 | int nativeHandle; 24 | }; 25 | 26 | Socket::Socket() : data(new PlatformData) { 27 | } 28 | 29 | Socket::~Socket() { 30 | shutdown(); 31 | delete data; 32 | } 33 | 34 | bool Socket::bind(int port) { 35 | ASSERT(port >= 0); 36 | ASSERT(port < 65536); 37 | if (!isValid()) { 38 | return false; 39 | } 40 | struct sockaddr_in sin; 41 | memset(&sin, 0, sizeof(sin)); 42 | sin.sin_family = AF_INET; 43 | sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 44 | sin.sin_port = htons(static_cast(port)); 45 | int result = ::bind( 46 | data->nativeHandle, reinterpret_cast(&sin), sizeof(sin)); 47 | return result == 0; 48 | } 49 | 50 | 51 | bool Socket::listen(int backlog) { 52 | if (!isValid()) { 53 | return false; 54 | } 55 | int result = ::listen(data->nativeHandle, backlog); 56 | return result == 0; 57 | } 58 | 59 | 60 | Socket* Socket::accept() { 61 | if (!isValid()) { 62 | return nullptr; 63 | } 64 | while (true) { 65 | int native_handle = ::accept(data->nativeHandle, nullptr, nullptr); 66 | if (native_handle == InvalidNativeHandle) { 67 | if (errno == EINTR) { 68 | continue; 69 | } 70 | return nullptr; 71 | } 72 | return new Socket(new PlatformData(native_handle)); 73 | } 74 | } 75 | 76 | 77 | bool Socket::connect(const char* host, const char* port) { 78 | ASSERT(nullptr != host); 79 | ASSERT(nullptr != port); 80 | if (!isValid()) { 81 | return false; 82 | } 83 | 84 | struct addrinfo* info = nullptr; 85 | struct addrinfo hint; 86 | memset(&hint, 0, sizeof(hint)); 87 | hint.ai_family = AF_INET; 88 | hint.ai_socktype = SOCK_STREAM; 89 | hint.ai_protocol = IPPROTO_TCP; 90 | int result = ::getaddrinfo(host, port, &hint, &info); 91 | if (result != 0) { 92 | return false; 93 | } 94 | 95 | for (struct addrinfo* ai = info; ai != nullptr; ai = ai->ai_next) { 96 | while (true) { 97 | result = ::connect( 98 | data->nativeHandle, ai->ai_addr, static_cast(ai->ai_addrlen)); 99 | if (result == 0) { 100 | freeaddrinfo(info); 101 | return true; 102 | } 103 | if (errno == EINTR) { 104 | continue; 105 | } 106 | break; 107 | } 108 | } 109 | freeaddrinfo(info); 110 | return false; 111 | } 112 | 113 | 114 | bool Socket::shutdown() { 115 | if (!isValid()) { 116 | return false; 117 | } 118 | int result = ::shutdown(data->nativeHandle, SHUT_RDWR); 119 | ::close(data->nativeHandle); 120 | data->nativeHandle = InvalidNativeHandle; 121 | return result == 0; 122 | } 123 | 124 | 125 | int Socket::send(const char* buffer, int length) { 126 | static int value = 1; 127 | setsockopt(data->nativeHandle, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value)); 128 | ASSERT(length <= 0 || buffer != nullptr); 129 | if (!isValid()) { 130 | return 0; 131 | } 132 | size_t offset = 0; 133 | while (offset < length) { 134 | auto result = ::send(data->nativeHandle, buffer + offset, length - offset, 0); 135 | if (result == 0) { 136 | break; 137 | } else if (result > 0) { 138 | ASSERT(result <= length - offset); 139 | offset += result; 140 | } else { 141 | if (errno == EINTR) { 142 | continue; 143 | } 144 | return 0; 145 | } 146 | } 147 | return static_cast(offset); 148 | } 149 | 150 | 151 | int Socket::receive(char* buffer, int length) { 152 | if (!isValid()) { 153 | return 0; 154 | } 155 | if (length <= 0) { 156 | return 0; 157 | } 158 | ASSERT(nullptr != buffer); 159 | while (true) { 160 | auto result = ::recv(data->nativeHandle, buffer, static_cast(length), 0); 161 | if (result < 0) { 162 | if (errno == EINTR) { 163 | continue; 164 | } 165 | return 0; 166 | } 167 | return static_cast(result); 168 | } 169 | } 170 | 171 | 172 | bool Socket::setReuseAddress(bool reuse_address) { 173 | if (!isValid()) { 174 | return 0; 175 | } 176 | int v = reuse_address ? 1 : 0; 177 | int result = ::setsockopt(data->nativeHandle, SOL_SOCKET, SO_REUSEADDR, 178 | reinterpret_cast(&v), sizeof(v)); 179 | return result == 0; 180 | } 181 | 182 | bool Socket::isValid() const { 183 | return data->nativeHandle != InvalidNativeHandle; 184 | } 185 | 186 | int Socket::getLastError() { 187 | return errno; 188 | } 189 | 190 | -------------------------------------------------------------------------------- /src/js/JSTest.js: -------------------------------------------------------------------------------- 1 | var RectangleJS = (function () { 2 | function RectangleJS(x, y, width, height) { 3 | if (x === void 0) { 4 | x = 0; 5 | } 6 | if (y === void 0) { 7 | y = 0; 8 | } 9 | if (width === void 0) { 10 | width = 0; 11 | } 12 | if (height === void 0) { 13 | height = 0; 14 | } 15 | this.x = x; 16 | this.y = y; 17 | this.width = width; 18 | this.height = height; 19 | } 20 | 21 | RectangleJS.prototype.setTo = function (x, y, width, height) { 22 | this.x = x; 23 | this.y = y; 24 | this.width = width; 25 | this.height = height; 26 | return this; 27 | }; 28 | RectangleJS.prototype.toString = function () { 29 | return "(x=" + this.x + ", y=" + this.y + ", width=" + this.width + ", height=" + this.height + ")"; 30 | }; 31 | return RectangleJS; 32 | })(); 33 | 34 | var MatrixJS = (function () { 35 | function MatrixJS(a, b, c, d, tx, ty) { 36 | if (a === void 0) { 37 | a = 1; 38 | } 39 | if (b === void 0) { 40 | b = 0; 41 | } 42 | if (c === void 0) { 43 | c = 0; 44 | } 45 | if (d === void 0) { 46 | d = 1; 47 | } 48 | if (tx === void 0) { 49 | tx = 0; 50 | } 51 | if (ty === void 0) { 52 | ty = 0; 53 | } 54 | this.a = a; 55 | this.b = b; 56 | this.c = c; 57 | this.d = d; 58 | this.tx = tx; 59 | this.ty = ty; 60 | } 61 | 62 | MatrixJS.prototype.setTo = function (a, b, c, d, tx, ty) { 63 | this.a = a; 64 | this.b = b; 65 | this.c = c; 66 | this.d = d; 67 | this.tx = tx; 68 | this.ty = ty; 69 | return this; 70 | }; 71 | MatrixJS.prototype.toString = function () { 72 | return "(a=" + this.a + ", b=" + this.b + ", c=" + this.c + ", d=" + this.d + ", tx=" + this.tx + ", ty=" + this.ty + ")"; 73 | }; 74 | MatrixJS.prototype.transformBounds = function (bounds) { 75 | var a = this.a; 76 | var b = this.b; 77 | var c = this.c; 78 | var d = this.d; 79 | var tx = this.tx; 80 | var ty = this.ty; 81 | var x = bounds.x; 82 | var y = bounds.y; 83 | var xMax = x + bounds.width; 84 | var yMax = y + bounds.height; 85 | var x0 = a * x + c * y + tx; 86 | var y0 = b * x + d * y + ty; 87 | var x1 = a * xMax + c * y + tx; 88 | var y1 = b * xMax + d * y + ty; 89 | var x2 = a * xMax + c * yMax + tx; 90 | var y2 = b * xMax + d * yMax + ty; 91 | var x3 = a * x + c * yMax + tx; 92 | var y3 = b * x + d * yMax + ty; 93 | var tmp = 0; 94 | if (x0 > x1) { 95 | tmp = x0; 96 | x0 = x1; 97 | x1 = tmp; 98 | } 99 | if (x2 > x3) { 100 | tmp = x2; 101 | x2 = x3; 102 | x3 = tmp; 103 | } 104 | bounds.x = Math.floor(x0 < x2 ? x0 : x2); 105 | bounds.width = Math.ceil((x1 > x3 ? x1 : x3) - bounds.x); 106 | if (y0 > y1) { 107 | tmp = y0; 108 | y0 = y1; 109 | y1 = tmp; 110 | } 111 | if (y2 > y3) { 112 | tmp = y2; 113 | y2 = y3; 114 | y3 = tmp; 115 | } 116 | bounds.y = Math.floor(y0 < y2 ? y0 : y2); 117 | bounds.height = Math.ceil((y1 > y3 ? y1 : y3) - bounds.y); 118 | }; 119 | return MatrixJS; 120 | })(); 121 | 122 | function transformBoundsNoField(x, y, width, height) { 123 | var a = 2; 124 | var b = 0; 125 | var c = 0; 126 | var d = 0.5; 127 | var tx = 11; 128 | var ty = 19; 129 | var xMax = x + width; 130 | var yMax = y + height; 131 | var x0 = a * x + c * y + tx; 132 | var y0 = b * x + d * y + ty; 133 | var x1 = a * xMax + c * y + tx; 134 | var y1 = b * xMax + d * y + ty; 135 | var x2 = a * xMax + c * yMax + tx; 136 | var y2 = b * xMax + d * yMax + ty; 137 | var x3 = a * x + c * yMax + tx; 138 | var y3 = b * x + d * yMax + ty; 139 | var tmp = 0; 140 | if (x0 > x1) { 141 | tmp = x0; 142 | x0 = x1; 143 | x1 = tmp; 144 | } 145 | if (x2 > x3) { 146 | tmp = x2; 147 | x2 = x3; 148 | x3 = tmp; 149 | } 150 | x = Math.floor(x0 < x2 ? x0 : x2); 151 | width = Math.ceil((x1 > x3 ? x1 : x3) - x); 152 | if (y0 > y1) { 153 | tmp = y0; 154 | y0 = y1; 155 | y1 = tmp; 156 | } 157 | if (y2 > y3) { 158 | tmp = y2; 159 | y2 = y3; 160 | y3 = tmp; 161 | } 162 | y = Math.floor(y0 < y2 ? y0 : y2); 163 | height = Math.ceil((y1 > y3 ? y1 : y3) - y); 164 | }; 165 | 166 | 167 | var rectJS = new RectangleJS(); 168 | var matrixJS = new MatrixJS(2, 0, 0, 0.5, 11, 19); 169 | var rect = new Rectangle(); 170 | var matrix = new Matrix(2, 0, 0, 0.5, 11, 19); 171 | 172 | var TIMES = 10; 173 | var SIZE = 100000; 174 | 175 | var data = []; 176 | var i, t, x, y, width, height, index, start; 177 | for (i = 0; i < SIZE; i++) { 178 | x = parseInt(Math.random() * 100); 179 | y = parseInt(Math.random() * 100); 180 | width = parseInt(Math.random() * 100); 181 | height = parseInt(Math.random() * 100); 182 | data.push(x, y, width, height); 183 | } 184 | data = new Int16Array(data); 185 | 186 | //JS测试 187 | start = Date.now(); 188 | for (t = 0; t < TIMES; t++) { 189 | index = 0; 190 | for (i = 0; i < SIZE; i++) { 191 | x = data[index++]; 192 | y = data[index++]; 193 | width = data[index++]; 194 | height = data[index++]; 195 | rectJS.setTo(x, y, width, height); 196 | matrixJS.transformBounds(rectJS); 197 | } 198 | } 199 | var jsTime = Date.now() - start; 200 | console.log("JS耗时:" + jsTime + "ms"); 201 | 202 | //JS-NoProp测试 203 | start = Date.now(); 204 | for (t = 0; t < TIMES; t++) { 205 | index = 0; 206 | for (i = 0; i < SIZE; i++) { 207 | x = data[index++]; 208 | y = data[index++]; 209 | width = data[index++]; 210 | height = data[index++]; 211 | transformBoundsNoField(x, y, width, height); 212 | } 213 | } 214 | var jsTime = Date.now() - start; 215 | console.log("JS-NoField耗时:" + jsTime + "ms"); 216 | 217 | //JSBinding测试 218 | start = Date.now(); 219 | for (t = 0; t < TIMES; t++) { 220 | index = 0; 221 | for (i = 0; i < SIZE; i++) { 222 | x = data[index++]; 223 | y = data[index++]; 224 | width = data[index++]; 225 | height = data[index++]; 226 | rect.setTo(x, y, width, height); 227 | matrix.transformBounds(rect); 228 | } 229 | } 230 | var jsBindingTime = Date.now() - start; 231 | console.log("JSBinding耗时:" + jsBindingTime + "ms"); 232 | 233 | //Native测试 234 | runtNativeTest(data, TIMES); 235 | 236 | 237 | 238 | -------------------------------------------------------------------------------- /src/debug/DebugAgent.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "DebugAgent.h" 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | inline static int VSNPrintF(char* buffer, int size, const char* format, va_list args) { 9 | int n = vsnprintf(buffer, static_cast(size), format, args); 10 | if (n < 0 || n >= size) { 11 | // If the length is zero, the assignment fails. 12 | if (size > 0) 13 | buffer[size - 1] = '\0'; 14 | return -1; 15 | } else { 16 | return n; 17 | } 18 | } 19 | 20 | inline static int SNPrintF(char* buffer, int size, const char* format, ...) { 21 | va_list args; 22 | va_start(args, format); 23 | int result = VSNPrintF(buffer, size, format, args); 24 | va_end(args); 25 | return result; 26 | } 27 | 28 | static const char* ContentLength = "Content-Length"; 29 | 30 | // Receive the full buffer before returning unless an error occours. 31 | static int ReceiveAll(Socket* conn, char* data, int len) { 32 | int total_received = 0; 33 | while (total_received < len) { 34 | int received = conn->receive(data + total_received, len - total_received); 35 | if (received == 0) { 36 | return total_received; 37 | } 38 | total_received += received; 39 | } 40 | return total_received; 41 | } 42 | 43 | static std::string ReceiveMessage(Socket* conn) { 44 | int received; 45 | 46 | // Read header. 47 | int content_length = 0; 48 | while (true) { 49 | const int kHeaderBufferSize = 80; 50 | char header_buffer[kHeaderBufferSize]; 51 | int header_buffer_position = 0; 52 | char c = '\0'; // One character receive buffer. 53 | char prev_c = '\0'; // Previous character. 54 | 55 | // Read until CRLF. 56 | while (!(c == '\n' && prev_c == '\r')) { 57 | prev_c = c; 58 | received = conn->receive(&c, 1); 59 | if (received == 0) { 60 | return ""; 61 | } 62 | 63 | // Add character to header buffer. 64 | if (header_buffer_position < kHeaderBufferSize) { 65 | header_buffer[header_buffer_position++] = c; 66 | } 67 | } 68 | 69 | // Check for end of header (empty header line). 70 | if (header_buffer_position == 2) { // Receive buffer contains CRLF. 71 | break; 72 | } 73 | 74 | // Terminate header. 75 | ASSERT(header_buffer_position > 1); // At least CRLF is received. 76 | ASSERT(header_buffer_position <= kHeaderBufferSize); 77 | header_buffer[header_buffer_position - 2] = '\0'; 78 | 79 | // Split header. 80 | char* key = header_buffer; 81 | char* value = nullptr; 82 | for (int i = 0; header_buffer[i] != '\0'; i++) { 83 | if (header_buffer[i] == ':') { 84 | header_buffer[i] = '\0'; 85 | value = header_buffer + i + 1; 86 | while (*value == ' ') { 87 | value++; 88 | } 89 | break; 90 | } 91 | } 92 | 93 | // Check that key is Content-Length. 94 | if (strcmp(key, ContentLength) == 0) { 95 | // Get the content length value if present and within a sensible range. 96 | if (value == nullptr || strlen(value) > 7) { 97 | return std::string(); 98 | } 99 | for (int i = 0; value[i] != '\0'; i++) { 100 | // Bail out if illegal data. 101 | if (value[i] < '0' || value[i] > '9') { 102 | return std::string(); 103 | } 104 | content_length = 10 * content_length + (value[i] - '0'); 105 | } 106 | } else { 107 | // For now just print all other headers than Content-Length. 108 | LOG("%s: %s\n", key, value != nullptr ? value : "(no value)"); 109 | } 110 | } 111 | 112 | // Return now if no body. 113 | if (content_length == 0) { 114 | return std::string(); 115 | } 116 | 117 | // Read body. 118 | char buffer[content_length + 1]; 119 | received = ReceiveAll(conn, buffer, content_length); 120 | if (received < content_length) { 121 | return std::string(); 122 | } 123 | buffer[content_length] = '\0'; 124 | 125 | return std::string(buffer); 126 | } 127 | 128 | 129 | static bool SendConnectMessage(Socket* conn, 130 | const char* embedding_host) { 131 | static const int BUFFER_SIZE = 80; 132 | char buffer[BUFFER_SIZE]; // Sending buffer. 133 | int ok; 134 | int len; 135 | 136 | // Send the header. 137 | len = SNPrintF(buffer, BUFFER_SIZE, 138 | "Type: connect\r\n"); 139 | ok = conn->send(buffer, len); 140 | if (!ok) return false; 141 | 142 | len = SNPrintF(buffer, BUFFER_SIZE, 143 | "V8-Version: %s\r\n", v8::V8::GetVersion()); 144 | ok = conn->send(buffer, len); 145 | if (!ok) return false; 146 | 147 | len = SNPrintF(buffer, BUFFER_SIZE, 148 | "Protocol-Version: 1\r\n"); 149 | ok = conn->send(buffer, len); 150 | if (!ok) return false; 151 | 152 | if (embedding_host != nullptr) { 153 | len = SNPrintF(buffer, BUFFER_SIZE, 154 | "Embedding-Host: %s\r\n", embedding_host); 155 | ok = conn->send(buffer, len); 156 | if (!ok) return false; 157 | } 158 | 159 | len = SNPrintF(buffer, BUFFER_SIZE, 160 | "%s: 0\r\n", ContentLength); 161 | ok = conn->send(buffer, len); 162 | if (!ok) return false; 163 | 164 | // Terminate header with empty line. 165 | len = SNPrintF(buffer, BUFFER_SIZE, "\r\n"); 166 | ok = conn->send(buffer, len); 167 | return static_cast(ok); 168 | } 169 | 170 | DebugAgent* DebugAgent::debugAgent = nullptr; 171 | 172 | void DebugAgent::Enable(const std::string& hostName, int port, bool waitForConnection) { 173 | ASSERT(debugAgent == nullptr); 174 | if (debugAgent) { 175 | return; 176 | } 177 | auto isolate = v8::Isolate::GetCurrent(); 178 | ASSERT(isolate != nullptr); 179 | debugAgent = new DebugAgent(isolate, hostName, port, waitForConnection); 180 | } 181 | 182 | void DebugAgent::Disable() { 183 | if (debugAgent) { 184 | delete debugAgent; 185 | debugAgent = nullptr; 186 | } 187 | } 188 | 189 | /** 190 | * Public V8 debugger API message handler function. This function just delegates to the debugger agent through it's 191 | * data parameter. 192 | */ 193 | void DebugAgentMessageHandler(const v8::Debug::Message& message) { 194 | DebugAgent::debugAgent->onDebugMessage(message); 195 | } 196 | 197 | 198 | DebugAgent::DebugAgent(v8::Isolate* isolate, const std::string& hostName, int port, bool waitForConnection) 199 | : isolate(isolate), hostName(hostName), port(port), server(new Socket), 200 | client(nullptr), terminate(false) { 201 | 202 | // Allow this socket to reuse port even if still in TIME_WAIT. 203 | server->setReuseAddress(true); 204 | 205 | // First bind the socket to the requested port. 206 | bool bound = server->bind(port); 207 | if (!bound) { 208 | LOG("Failed to open socket on port %d, ", port); 209 | return; 210 | } 211 | v8::Debug::SetMessageHandler(isolate, DebugAgentMessageHandler); 212 | if (waitForConnection) { 213 | 214 | if (server->listen(1)) { 215 | // Accept the new connection. 216 | client = server->accept(); 217 | if (client) { 218 | v8::Debug::DebugBreak(isolate); 219 | // Create and start a new session. 220 | thread = std::thread(std::bind(&DebugAgent::runClientLoop, this)); 221 | } 222 | } 223 | } 224 | else { 225 | thread = std::thread(std::bind(&DebugAgent::runClientLoop, this)); 226 | } 227 | 228 | } 229 | 230 | 231 | DebugAgent::~DebugAgent() { 232 | v8::Debug::SetMessageHandler(isolate, nullptr); 233 | v8::Debug::CancelDebugBreak(isolate); 234 | terminate = true; 235 | delete server; 236 | server = nullptr; 237 | delete client; 238 | client = nullptr; 239 | thread.join(); 240 | } 241 | 242 | void DebugAgent::runClientLoop() { 243 | while (true) { 244 | if (!client) { 245 | // Wait for connection 246 | if (server->listen(1)); 247 | // Accept the new connection. 248 | client = server->accept(); 249 | if (!client) { 250 | return; 251 | } 252 | } 253 | // Send the hello message. 254 | bool ok = SendConnectMessage(client, hostName.c_str()); 255 | if (!ok) { 256 | return; 257 | } 258 | 259 | // Read data from the debugger front end. 260 | std::string message = 261 | ReceiveMessage(client); 262 | if (terminate) { 263 | return; 264 | } 265 | const char* msg = message.c_str(); 266 | bool closed = (message.length() == 0); 267 | 268 | if (closed) { 269 | // If we lost the connection, then simulate a disconnect msg: 270 | msg = "{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}"; 271 | 272 | } else { 273 | // Check if we're getting a disconnect request: 274 | const char* disconnectRequestStr = 275 | "\"type\":\"request\",\"command\":\"disconnect\"}"; 276 | const char* result = strstr(msg, disconnectRequestStr); 277 | if (result != nullptr) { 278 | closed = true; 279 | } 280 | } 281 | 282 | std::wstring_convert, char16_t> convert; 283 | std::u16string dest = convert.from_bytes(msg); 284 | v8::Debug::SendCommand(isolate, reinterpret_cast(dest.c_str()), 285 | static_cast(dest.length())); 286 | if (closed) { 287 | v8::Debug::CancelDebugBreak(isolate); 288 | delete client; 289 | client = nullptr; 290 | } 291 | } 292 | } 293 | 294 | void DebugAgent::onDebugMessage(const v8::Debug::Message& message) { 295 | if (client == nullptr) { 296 | return; 297 | } 298 | v8::HandleScope scope(message.GetIsolate()); 299 | static const int kBufferSize = 80; 300 | char buffer[kBufferSize]; // Sending buffer both for header and body. 301 | 302 | // Convert the request to UTF-8 encoding. 303 | v8::String::Utf8Value utf8_request(message.GetJSON()); 304 | 305 | // Send the header. 306 | int len = SNPrintF(buffer, kBufferSize, 307 | "Content-Length: %d\r\n", utf8_request.length()); 308 | if (client->send(buffer, len) < len) { 309 | return; 310 | } 311 | 312 | // Terminate header with empty line. 313 | len = SNPrintF(buffer, kBufferSize, "\r\n"); 314 | if (client->send(buffer, len) < len) { 315 | return; 316 | } 317 | 318 | // Send message body as UTF-8. 319 | len = utf8_request.length(); 320 | client->send(*utf8_request, len); 321 | } --------------------------------------------------------------------------------