diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2018-08-20 17:36:29 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2018-08-20 17:37:22 +0100 |
commit | 53c3de3575351bd1892a203932ffc1288e8e9640 (patch) | |
tree | 2e00e38f3f24210933a3cb805ab0cfc6e6b5fbac | |
parent | 55f066e8d50760bbd1493e46bb62258a9afd41d4 (diff) |
igt/shell: Bare v8 baselineigt-shell
-rw-r--r-- | meson.build | 7 | ||||
-rw-r--r-- | shell/meson.build | 6 | ||||
-rw-r--r-- | shell/v8-shell.cc | 314 |
3 files changed, 326 insertions, 1 deletions
diff --git a/meson.build b/meson.build index 7d7072bd..527574eb 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('igt-gpu-tools', 'c', +project('igt-gpu-tools', [ 'c', 'cpp' ], version : '1.23', default_options: [ 'warning_level=2', @@ -8,6 +8,7 @@ project('igt-gpu-tools', 'c', meson_version : '>=0.44.0') cc = meson.get_compiler('c') +cxx = meson.get_compiler('cpp') cc_args = [ '-Wno-unused-parameter', @@ -24,6 +25,9 @@ foreach cc_arg : cc_args if cc.has_argument(cc_arg) add_global_arguments(cc_arg, language : 'c') endif + if cxx.has_argument(cc_arg) + add_global_arguments(cc_arg, language : 'cpp') + endif endforeach _build_overlay = false @@ -104,6 +108,7 @@ libkmod = dependency('libkmod') libprocps = dependency('libprocps', required : true) libunwind = dependency('libunwind', required : true) ssl = dependency('openssl', required : true) +v8 = cxx.find_library('v8') valgrind = null_dep valgrindinfo = 'No' diff --git a/shell/meson.build b/shell/meson.build index ee11b0b5..8eb06b71 100644 --- a/shell/meson.build +++ b/shell/meson.build @@ -1,3 +1,9 @@ +executable('v8', [ + 'v8-shell.cc', + ], dependencies : [ v8, math, libkmod ], + include_directories : include_directories('include', '../include') +) + executable('igt', [ 'duktape/duktape.c', 'drm/drm-constants.c', diff --git a/shell/v8-shell.cc b/shell/v8-shell.cc new file mode 100644 index 00000000..1e10c512 --- /dev/null +++ b/shell/v8-shell.cc @@ -0,0 +1,314 @@ +#include <v8.h> +#include <fcntl.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/utsname.h> +#include <unistd.h> + +#include "../lib/version.h" +#include "../config.h" + +const char* ToCString(const v8::String::Utf8Value& value) { + return *value ? *value : "<invalid string>"; +} + +v8::Handle<v8::Value> Print(const v8::Arguments& args) +{ + for (int i = 0; i < args.Length(); i++) { + v8::HandleScope handle_scope; + v8::String::Utf8Value str(args[i]); + printf("%s%s", i ? " " : "", ToCString(str)); + } + printf("\n"); + fflush(stdout); + + return v8::Undefined(); +} + +v8::Handle<v8::String> ReadFile(const char *name) +{ + FILE *file = fopen(name, "rb"); + if (file == NULL) + return v8::Handle<v8::String>(); + + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + rewind(file); + + char *buf = new char[size + 1]; + size_t i = 0; + while (i < size) { + size_t r = fread(buf + i, 1, size - i, file); + if (!r) + break; + + i += r; + } + buf[i] = '\0'; + fclose(file); + + v8::Handle<v8::String> result = v8::String::New(buf, i); + delete[] buf; + + return result; +} + +v8::Handle<v8::Value> Read(const v8::Arguments& args) +{ + if (args.Length() != 1) + return v8::ThrowException(v8::String::New("Bad parameters")); + + v8::String::Utf8Value file(args[0]); + if (*file == NULL) + return v8::ThrowException(v8::String::New("Error loading file")); + + v8::Handle<v8::String> source = ReadFile(*file); + if (source.IsEmpty()) + return v8::ThrowException(v8::String::New("Error loading file")); + + return source; +} + +v8::Handle<v8::Value> Quit(const v8::Arguments& args) { + fflush(stdout); + fflush(stderr); + exit(args[0]->Int32Value()); + return v8::Undefined(); +} + +void ReportException(v8::TryCatch* try_catch) { + v8::HandleScope handle_scope; + + v8::String::Utf8Value exception(try_catch->Exception()); + const char* exception_string = ToCString(exception); + + v8::Handle<v8::Message> message = try_catch->Message(); + if (message.IsEmpty()) { + printf("%s\n", exception_string); + } else { + v8::String::Utf8Value filename(message->GetScriptResourceName()); + printf("%s:%i: %s\n", + ToCString(filename), message->GetLineNumber(), exception_string); + + v8::String::Utf8Value sourceline(message->GetSourceLine()); + printf("%s\n", ToCString(sourceline)); + + int start = message->GetStartColumn(); + for (int i = 0; i < start; i++) + printf(" "); + + int end = message->GetEndColumn(); + for (int i = start; i < end; i++) + printf("^"); + + printf("\n"); + + v8::String::Utf8Value stack_trace(try_catch->StackTrace()); + if (stack_trace.length() > 0) + printf("%s\n", ToCString(stack_trace)); + } +} + +bool ExecuteString(v8::Handle<v8::String> source, + v8::Handle<v8::Value> name, + bool print_result, + bool report_exceptions) +{ + v8::HandleScope handle_scope; + v8::TryCatch try_catch; + + v8::Handle<v8::Script> script = v8::Script::Compile(source, name); + if (script.IsEmpty()) { + if (report_exceptions) + ReportException(&try_catch); + return false; + } + + v8::Handle<v8::Value> result = script->Run(); + if (result.IsEmpty()) { + if (report_exceptions) + ReportException(&try_catch); + return false; + } + + if (print_result && !result->IsUndefined()) { + v8::String::Utf8Value str(result); + printf("%s\n", ToCString(str)); + } + + return true; +} + +v8::Handle<v8::Value> Load(const v8::Arguments& args) { + for (int i = 0; i < args.Length(); i++) { + v8::HandleScope handle_scope; + + v8::String::Utf8Value file(args[i]); + if (*file == NULL) + return v8::ThrowException(v8::String::New("Error loading file")); + + v8::Handle<v8::String> source = ReadFile(*file); + if (source.IsEmpty()) + return v8::ThrowException(v8::String::New("Error loading file")); + + if (!ExecuteString(source, v8::String::New(*file), false, false)) + return v8::ThrowException(v8::String::New("Error executing file")); + } + + return v8::Undefined(); +} + +v8::Persistent<v8::Context> ShellContext() +{ + v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); + +#if 1 + static const struct { + const char *name; + v8::Handle<v8::Value> (*fn)(const v8::Arguments&); + } globals[] = { + { "print", Print }, + { "read", Read }, + { "load", Load }, + { "quit", Quit }, + { }, + }; + for (typeof(*globals) *g = globals; g->name; g++) + global->Set(v8::String::New(g->name), v8::FunctionTemplate::New(g->fn)); +#endif + + return v8::Context::New(NULL, global); +} + +void print_welcome() +{ + struct utsname uts; + + uname(&uts); + printf("IGT Version: %s-%s (%s) (%s: %s %s)\n", + PACKAGE_VERSION, IGT_GIT_SHA1, TARGET_CPU_PLATFORM, + uts.sysname, uts.release, uts.machine); + printf("V8: %s\n", v8::V8::GetVersion()); +} + +int do_eval(v8::Handle<v8::Context> ctx, const char *str) +{ + v8::Handle<v8::String> filename = v8::String::New("cmdline"); + v8::Handle<v8::String> source = v8::String::New(str); + return !ExecuteString(source, filename, false, true); +} + +int run(v8::Handle<v8::Context> ctx, int argc, char **argv) +{ + while (++optind < argc) { + const char *str = argv[optind]; + v8::Handle<v8::String> file_name = v8::String::New(str); + v8::Handle<v8::String> source = ReadFile(str); + if (source.IsEmpty()) { + printf("Error reading '%s'\n", str); + continue; + } + + if (!ExecuteString(source, file_name, false, true)) + return 1; + } + + return 0; +} + +int shell(v8::Handle<v8::Context> ctx, int argc, char **argv) +{ + print_welcome(); + + static const int kBufferSize = 256; + + // Enter the execution environment before evaluating any code. + v8::Context::Scope context_scope(ctx); + v8::Local<v8::String> name(v8::String::New("(shell)")); + +#if 0 + static const struct { + const char *name; + v8::Handle<v8::Value> (*fn)(const v8::Arguments&); + } globals[] = { + { "print", Print }, + { "read", Read }, + { "load", Load }, + { "quit", Quit }, + { }, + }; + for (typeof(*globals) *g = globals; g->name; g++) { + v8::Handle<v8::String> name(v8::String::New(g->name)); + v8::Local<v8::Function> fn(v8::Function::New(g->fn)); + ctx->Global()->Set(name, fn); + } +#endif + while (true) { + char buffer[kBufferSize]; + + printf("igt> "); + char *str = fgets(buffer, kBufferSize, stdin); + if (str == NULL) + break; + + v8::HandleScope handle_scope; + ExecuteString(v8::String::New(str), name, true, true); + } + + printf("\n"); + return 0; +} + +int main(int argc, char* argv[]) +{ + v8::V8::SetFlagsFromCommandLine(&argc, argv, true); + int err, opt; + + { + v8::HandleScope handle_scope; + v8::Persistent<v8::Context> ctx = ShellContext(); + if (ctx.IsEmpty()) { + fprintf(stderr, "Error creating V8 context\n"); + return 1; + } + + ctx->Enter(); + + while ((opt = getopt(argc, argv, "e:")) != -1) { + switch (opt) { + case 'e': + if (do_eval(ctx, optarg)) + goto err; + break; + } + } + + if (optind < argc) { + static const struct target { + const char *name; + int (*func)(v8::Handle<v8::Context>, int, char **); + } targets[] = { + { "shell", shell }, + { "run", run }, + { } + }; + for (typeof(*targets) *t = targets; t->name; t++) { + if (!strcmp(argv[optind], t->name)) { + err = t->func(ctx, argc, argv); + goto err; + } + } + fprintf(stderr, "Unrecognised command '%s'\n", argv[optind]); + } else { + err = shell(ctx, 0, NULL); + } + +err: + ctx->Exit(); + ctx.Dispose(); + } + + v8::V8::Dispose(); + return err; +} |