diff options
author | Torne (Richard Coles) <torne@google.com> | 2014-03-18 10:20:56 +0000 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2014-03-18 10:20:56 +0000 |
commit | a1401311d1ab56c4ed0a474bd38c108f75cb0cd9 (patch) | |
tree | 3437151d9ae1ce20a1e53a0d98c19ca01c786394 /gin | |
parent | af5066f1e36c6579e74752647e6c584438f80f94 (diff) | |
download | chromium_org-a1401311d1ab56c4ed0a474bd38c108f75cb0cd9.tar.gz |
Merge from Chromium at DEPS revision 257591
This commit was generated by merge_to_master.py.
Change-Id: I0010df2ec3fbb5d4947cd026de2feb150ce7a6b5
Diffstat (limited to 'gin')
47 files changed, 1267 insertions, 324 deletions
diff --git a/gin/arguments.h b/gin/arguments.h index ec4ae80e88..509c22ca14 100644 --- a/gin/arguments.h +++ b/gin/arguments.h @@ -56,6 +56,17 @@ class GIN_EXPORT Arguments { return true; } + bool Skip() { + if (next_ >= info_->Length()) + return false; + next_++; + return true; + } + + int Length() const { + return info_->Length(); + } + template<typename T> void Return(T val) { info_->GetReturnValue().Set(ConvertToV8(isolate_, val)); diff --git a/gin/array_buffer.cc b/gin/array_buffer.cc index ee9f2a5867..68237bcbf8 100644 --- a/gin/array_buffer.cc +++ b/gin/array_buffer.cc @@ -2,17 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "gin/array_buffer.h" - #include <stdlib.h> +#include "base/logging.h" +#include "gin/array_buffer.h" +#include "gin/per_isolate_data.h" + namespace gin { +namespace { + +gin::WrapperInfo g_array_buffer_wrapper_info = {gin::kEmbedderNativeGin}; + +} // namespace + COMPILE_ASSERT(V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT == 2, array_buffers_must_have_two_internal_fields); -static const int kBufferViewPrivateIndex = 0; - // ArrayBufferAllocator ------------------------------------------------------- void* ArrayBufferAllocator::Allocate(size_t length) { @@ -72,6 +78,7 @@ class ArrayBuffer::Private : public base::RefCounted<ArrayBuffer::Private> { v8::Persistent<v8::ArrayBuffer> array_buffer_; scoped_refptr<Private> self_reference_; + v8::Isolate* isolate_; void* buffer_; size_t length_; }; @@ -79,28 +86,34 @@ class ArrayBuffer::Private : public base::RefCounted<ArrayBuffer::Private> { scoped_refptr<ArrayBuffer::Private> ArrayBuffer::Private::From( v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array) { if (array->IsExternal()) { + CHECK_EQ(WrapperInfo::From(v8::Handle<v8::Object>::Cast(array)), + &g_array_buffer_wrapper_info) + << "Cannot mix blink and gin ArrayBuffers"; return make_scoped_refptr(static_cast<Private*>( - array->GetAlignedPointerFromInternalField(kBufferViewPrivateIndex))); + array->GetAlignedPointerFromInternalField(kEncodedValueIndex))); } return make_scoped_refptr(new Private(isolate, array)); } ArrayBuffer::Private::Private(v8::Isolate* isolate, v8::Handle<v8::ArrayBuffer> array) - : array_buffer_(isolate, array) { + : array_buffer_(isolate, array), isolate_(isolate) { // Take ownership of the array buffer. + CHECK(!array->IsExternal()); v8::ArrayBuffer::Contents contents = array->Externalize(); buffer_ = contents.Data(); length_ = contents.ByteLength(); - array->SetAlignedPointerInInternalField(kBufferViewPrivateIndex, this); + array->SetAlignedPointerInInternalField(kWrapperInfoIndex, + &g_array_buffer_wrapper_info); + array->SetAlignedPointerInInternalField(kEncodedValueIndex, this); self_reference_ = this; // Cleared in WeakCallback. array_buffer_.SetWeak(this, WeakCallback); } ArrayBuffer::Private::~Private() { - ArrayBufferAllocator::SharedInstance()->Free(buffer_, length_); + PerIsolateData::From(isolate_)->allocator()->Free(buffer_, length_); } void ArrayBuffer::Private::WeakCallback( diff --git a/gin/context_holder.cc b/gin/context_holder.cc index fba2a2a8bf..241b25622c 100644 --- a/gin/context_holder.cc +++ b/gin/context_holder.cc @@ -14,17 +14,14 @@ ContextHolder::ContextHolder(v8::Isolate* isolate) } ContextHolder::~ContextHolder() { - v8::HandleScope handle_scope(isolate()); - v8::Handle<v8::Context> context = this->context(); - - data_->Detach(context); + // PerContextData needs to be destroyed before the context. data_.reset(); } void ContextHolder::SetContext(v8::Handle<v8::Context> context) { DCHECK(context_.IsEmpty()); context_.Reset(isolate_, context); - data_.reset(new PerContextData(context)); + data_.reset(new PerContextData(this, context)); } } // namespace gin diff --git a/gin/converter.cc b/gin/converter.cc index 07437b7edc..29da322c1a 100644 --- a/gin/converter.cc +++ b/gin/converter.cc @@ -35,7 +35,7 @@ Handle<Value> Converter<int32_t>::ToV8(Isolate* isolate, int32_t val) { bool Converter<int32_t>::FromV8(Isolate* isolate, Handle<Value> val, int32_t* out) { - if (!val->IsInt32()) + if (!val->IsNumber()) return false; *out = val->Int32Value(); return true; @@ -47,7 +47,7 @@ Handle<Value> Converter<uint32_t>::ToV8(Isolate* isolate, uint32_t val) { bool Converter<uint32_t>::FromV8(Isolate* isolate, Handle<Value> val, uint32_t* out) { - if (!val->IsUint32()) + if (!val->IsNumber()) return false; *out = val->Uint32Value(); return true; diff --git a/gin/converter.h b/gin/converter.h index 1ce459e15c..e5c95fc1f9 100644 --- a/gin/converter.h +++ b/gin/converter.h @@ -176,8 +176,7 @@ struct Converter<std::vector<T> > { // Convenience functions that deduce T. template<typename T> -v8::Handle<v8::Value> ConvertToV8(v8::Isolate* isolate, - T input) { +v8::Handle<v8::Value> ConvertToV8(v8::Isolate* isolate, T input) { return Converter<T>::ToV8(isolate, input); } diff --git a/gin/converter_unittest.cc b/gin/converter_unittest.cc index 791d7e66ec..cf1affc0e1 100644 --- a/gin/converter_unittest.cc +++ b/gin/converter_unittest.cc @@ -89,7 +89,7 @@ TEST_F(ConverterTest, Int32) { { Integer::New(instance_->isolate(), 0).As<Value>(), true, 0 }, { Integer::New(instance_->isolate(), 1).As<Value>(), true, 1 }, { Number::New(instance_->isolate(), -1).As<Value>(), true, -1 }, - { Number::New(instance_->isolate(), 1.1).As<Value>(), false, 0 }, + { Number::New(instance_->isolate(), 1.1).As<Value>(), true, 1 }, { String::NewFromUtf8(instance_->isolate(), "42").As<Value>(), false, 0 }, { String::NewFromUtf8(instance_->isolate(), "foo").As<Value>(), false, 0 }, { Object::New(instance_->isolate()).As<Value>(), false, 0 }, diff --git a/gin/function_template.h b/gin/function_template.h index fe95f519ef..7ba54b5910 100644 --- a/gin/function_template.h +++ b/gin/function_template.h @@ -501,6 +501,20 @@ v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( holder->GetHandle(isolate))); } +// CreateFunctionHandler installs a CallAsFunction handler on the given +// object template that forwards to a provided C++ function or base::Callback. +template<typename Sig> +void CreateFunctionHandler(v8::Isolate* isolate, + v8::Local<v8::ObjectTemplate> tmpl, + const base::Callback<Sig> callback, + int callback_flags = 0) { + typedef internal::CallbackHolder<Sig> HolderT; + HolderT* holder = new HolderT(isolate, callback, callback_flags); + tmpl->SetCallAsFunctionHandler(&internal::Dispatcher<Sig>::DispatchToCallback, + ConvertToV8<v8::Handle<v8::External> >( + isolate, holder->GetHandle(isolate))); +} + } // namespace gin #endif // GIN_FUNCTION_TEMPLATE_H_ diff --git a/gin/function_template.h.pump b/gin/function_template.h.pump index 6f5badee92..20b2821e0e 100644 --- a/gin/function_template.h.pump +++ b/gin/function_template.h.pump @@ -221,6 +221,20 @@ v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( holder->GetHandle(isolate))); } +// CreateFunctionHandler installs a CallAsFunction handler on the given +// object template that forwards to a provided C++ function or base::Callback. +template<typename Sig> +void CreateFunctionHandler(v8::Isolate* isolate, + v8::Local<v8::ObjectTemplate> tmpl, + const base::Callback<Sig> callback, + int callback_flags = 0) { + typedef internal::CallbackHolder<Sig> HolderT; + HolderT* holder = new HolderT(isolate, callback, callback_flags); + tmpl->SetCallAsFunctionHandler(&internal::Dispatcher<Sig>::DispatchToCallback, + ConvertToV8<v8::Handle<v8::External> >( + isolate, holder->GetHandle(isolate))); +} + } // namespace gin #endif // GIN_FUNCTION_TEMPLATE_H_ diff --git a/gin/gin.gyp b/gin/gin.gyp index 78c8fb1d97..1b15dd16c4 100644 --- a/gin/gin.gyp +++ b/gin/gin.gyp @@ -35,6 +35,8 @@ 'function_template.h', 'gin_export.h', 'handle.h', + 'interceptor.cc', + 'interceptor.h', 'isolate_holder.cc', 'modules/console.cc', 'modules/console.h', @@ -42,6 +44,7 @@ 'modules/file_module_provider.h', 'modules/module_registry.cc', 'modules/module_registry.h', + 'modules/module_registry_observer.h', 'modules/module_runner_delegate.cc', 'modules/module_runner_delegate.h', 'modules/timer.cc', @@ -58,6 +61,8 @@ 'public/wrapper_info.h', 'runner.cc', 'runner.h', + 'shell_runner.cc', + 'shell_runner.h', 'try_catch.cc', 'try_catch.h', 'wrappable.cc', @@ -114,10 +119,13 @@ ], 'sources': [ 'converter_unittest.cc', + 'interceptor_unittest.cc', + 'modules/module_registry_unittest.cc', 'modules/timer_unittest.cc', + 'per_context_data_unittest.cc', + 'shell_runner_unittest.cc', 'test/run_all_unittests.cc', 'test/run_js_tests.cc', - 'runner_unittest.cc', 'wrappable_unittest.cc', ], }, diff --git a/gin/gin.target.darwin-arm.mk b/gin/gin.target.darwin-arm.mk index 9da148631c..6d6bee45f1 100644 --- a/gin/gin.target.darwin-arm.mk +++ b/gin/gin.target.darwin-arm.mk @@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \ gin/converter.cc \ gin/dictionary.cc \ gin/function_template.cc \ + gin/interceptor.cc \ gin/isolate_holder.cc \ gin/modules/console.cc \ gin/modules/file_module_provider.cc \ @@ -40,6 +41,7 @@ LOCAL_SRC_FILES := \ gin/per_context_data.cc \ gin/per_isolate_data.cc \ gin/runner.cc \ + gin/shell_runner.cc \ gin/try_catch.cc \ gin/wrappable.cc \ gin/wrapper_info.cc @@ -82,6 +84,7 @@ MY_CFLAGS_Debug := \ MY_DEFS_Debug := \ '-DV8_DEPRECATION_WARNINGS' \ + '-DBLINK_SCALE_FILTERS_AT_RECORD_TIME' \ '-D_FILE_OFFSET_BITS=64' \ '-DNO_TCMALLOC' \ '-DDISABLE_NACL' \ @@ -89,14 +92,15 @@ MY_DEFS_Debug := \ '-DUSE_LIBJPEG_TURBO=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ + '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ - '-DUSE_OPENSSL=1' \ '-DENABLE_EGLIMAGE=1' \ '-DCLD_VERSION=1' \ '-DENABLE_PRINTING=1' \ '-DENABLE_MANAGED_USERS=1' \ '-DGIN_IMPLEMENTATION' \ + '-DUSE_OPENSSL=1' \ '-D__STDC_CONSTANT_MACROS' \ '-D__STDC_FORMAT_MACROS' \ '-DANDROID' \ @@ -169,6 +173,7 @@ MY_CFLAGS_Release := \ MY_DEFS_Release := \ '-DV8_DEPRECATION_WARNINGS' \ + '-DBLINK_SCALE_FILTERS_AT_RECORD_TIME' \ '-D_FILE_OFFSET_BITS=64' \ '-DNO_TCMALLOC' \ '-DDISABLE_NACL' \ @@ -176,14 +181,15 @@ MY_DEFS_Release := \ '-DUSE_LIBJPEG_TURBO=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ + '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ - '-DUSE_OPENSSL=1' \ '-DENABLE_EGLIMAGE=1' \ '-DCLD_VERSION=1' \ '-DENABLE_PRINTING=1' \ '-DENABLE_MANAGED_USERS=1' \ '-DGIN_IMPLEMENTATION' \ + '-DUSE_OPENSSL=1' \ '-D__STDC_CONSTANT_MACROS' \ '-D__STDC_FORMAT_MACROS' \ '-DANDROID' \ @@ -223,9 +229,11 @@ LOCAL_CPPFLAGS_Release := \ LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION)) LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION)) LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION)) +LOCAL_ASFLAGS := $(LOCAL_CFLAGS) ### Rules for final target. LOCAL_LDFLAGS_Debug := \ + -Wl,--fatal-warnings \ -Wl,-z,now \ -Wl,-z,relro \ -Wl,-z,noexecstack \ @@ -237,7 +245,6 @@ LOCAL_LDFLAGS_Debug := \ -Wl,--no-undefined \ -Wl,--exclude-libs=ALL \ -Wl,--icf=safe \ - -Wl,--fatal-warnings \ -Wl,--gc-sections \ -Wl,--warn-shared-textrel \ -Wl,-O1 \ @@ -245,6 +252,7 @@ LOCAL_LDFLAGS_Debug := \ LOCAL_LDFLAGS_Release := \ + -Wl,--fatal-warnings \ -Wl,-z,now \ -Wl,-z,relro \ -Wl,-z,noexecstack \ @@ -259,7 +267,6 @@ LOCAL_LDFLAGS_Release := \ -Wl,-O1 \ -Wl,--as-needed \ -Wl,--gc-sections \ - -Wl,--fatal-warnings \ -Wl,--warn-shared-textrel diff --git a/gin/gin.target.darwin-mips.mk b/gin/gin.target.darwin-mips.mk index da8b23434c..1e1588ff47 100644 --- a/gin/gin.target.darwin-mips.mk +++ b/gin/gin.target.darwin-mips.mk @@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \ gin/converter.cc \ gin/dictionary.cc \ gin/function_template.cc \ + gin/interceptor.cc \ gin/isolate_holder.cc \ gin/modules/console.cc \ gin/modules/file_module_provider.cc \ @@ -40,6 +41,7 @@ LOCAL_SRC_FILES := \ gin/per_context_data.cc \ gin/per_isolate_data.cc \ gin/runner.cc \ + gin/shell_runner.cc \ gin/try_catch.cc \ gin/wrappable.cc \ gin/wrapper_info.cc @@ -81,6 +83,7 @@ MY_CFLAGS_Debug := \ MY_DEFS_Debug := \ '-DV8_DEPRECATION_WARNINGS' \ + '-DBLINK_SCALE_FILTERS_AT_RECORD_TIME' \ '-D_FILE_OFFSET_BITS=64' \ '-DNO_TCMALLOC' \ '-DDISABLE_NACL' \ @@ -88,14 +91,15 @@ MY_DEFS_Debug := \ '-DUSE_LIBJPEG_TURBO=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ + '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ - '-DUSE_OPENSSL=1' \ '-DENABLE_EGLIMAGE=1' \ '-DCLD_VERSION=1' \ '-DENABLE_PRINTING=1' \ '-DENABLE_MANAGED_USERS=1' \ '-DGIN_IMPLEMENTATION' \ + '-DUSE_OPENSSL=1' \ '-D__STDC_CONSTANT_MACROS' \ '-D__STDC_FORMAT_MACROS' \ '-DANDROID' \ @@ -167,6 +171,7 @@ MY_CFLAGS_Release := \ MY_DEFS_Release := \ '-DV8_DEPRECATION_WARNINGS' \ + '-DBLINK_SCALE_FILTERS_AT_RECORD_TIME' \ '-D_FILE_OFFSET_BITS=64' \ '-DNO_TCMALLOC' \ '-DDISABLE_NACL' \ @@ -174,14 +179,15 @@ MY_DEFS_Release := \ '-DUSE_LIBJPEG_TURBO=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ + '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ - '-DUSE_OPENSSL=1' \ '-DENABLE_EGLIMAGE=1' \ '-DCLD_VERSION=1' \ '-DENABLE_PRINTING=1' \ '-DENABLE_MANAGED_USERS=1' \ '-DGIN_IMPLEMENTATION' \ + '-DUSE_OPENSSL=1' \ '-D__STDC_CONSTANT_MACROS' \ '-D__STDC_FORMAT_MACROS' \ '-DANDROID' \ @@ -221,9 +227,11 @@ LOCAL_CPPFLAGS_Release := \ LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION)) LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION)) LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION)) +LOCAL_ASFLAGS := $(LOCAL_CFLAGS) ### Rules for final target. LOCAL_LDFLAGS_Debug := \ + -Wl,--fatal-warnings \ -Wl,-z,now \ -Wl,-z,relro \ -Wl,-z,noexecstack \ @@ -233,7 +241,6 @@ LOCAL_LDFLAGS_Debug := \ -nostdlib \ -Wl,--no-undefined \ -Wl,--exclude-libs=ALL \ - -Wl,--fatal-warnings \ -Wl,--gc-sections \ -Wl,--warn-shared-textrel \ -Wl,-O1 \ @@ -241,6 +248,7 @@ LOCAL_LDFLAGS_Debug := \ LOCAL_LDFLAGS_Release := \ + -Wl,--fatal-warnings \ -Wl,-z,now \ -Wl,-z,relro \ -Wl,-z,noexecstack \ @@ -253,7 +261,6 @@ LOCAL_LDFLAGS_Release := \ -Wl,-O1 \ -Wl,--as-needed \ -Wl,--gc-sections \ - -Wl,--fatal-warnings \ -Wl,--warn-shared-textrel diff --git a/gin/gin.target.darwin-x86.mk b/gin/gin.target.darwin-x86.mk index f0d0cb4504..0e2450ca66 100644 --- a/gin/gin.target.darwin-x86.mk +++ b/gin/gin.target.darwin-x86.mk @@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \ gin/converter.cc \ gin/dictionary.cc \ gin/function_template.cc \ + gin/interceptor.cc \ gin/isolate_holder.cc \ gin/modules/console.cc \ gin/modules/file_module_provider.cc \ @@ -40,6 +41,7 @@ LOCAL_SRC_FILES := \ gin/per_context_data.cc \ gin/per_isolate_data.cc \ gin/runner.cc \ + gin/shell_runner.cc \ gin/try_catch.cc \ gin/wrappable.cc \ gin/wrapper_info.cc @@ -57,11 +59,10 @@ MY_CFLAGS_Debug := \ -fvisibility=hidden \ -pipe \ -fPIC \ - -m32 \ - -mmmx \ - -march=pentium4 \ -msse2 \ -mfpmath=sse \ + -mmmx \ + -m32 \ -fuse-ld=gold \ -ffunction-sections \ -funwind-tables \ @@ -84,6 +85,7 @@ MY_CFLAGS_Debug := \ MY_DEFS_Debug := \ '-DV8_DEPRECATION_WARNINGS' \ + '-DBLINK_SCALE_FILTERS_AT_RECORD_TIME' \ '-D_FILE_OFFSET_BITS=64' \ '-DNO_TCMALLOC' \ '-DDISABLE_NACL' \ @@ -91,14 +93,15 @@ MY_DEFS_Debug := \ '-DUSE_LIBJPEG_TURBO=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ + '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ - '-DUSE_OPENSSL=1' \ '-DENABLE_EGLIMAGE=1' \ '-DCLD_VERSION=1' \ '-DENABLE_PRINTING=1' \ '-DENABLE_MANAGED_USERS=1' \ '-DGIN_IMPLEMENTATION' \ + '-DUSE_OPENSSL=1' \ '-D__STDC_CONSTANT_MACROS' \ '-D__STDC_FORMAT_MACROS' \ '-DANDROID' \ @@ -145,11 +148,10 @@ MY_CFLAGS_Release := \ -fvisibility=hidden \ -pipe \ -fPIC \ - -m32 \ - -mmmx \ - -march=pentium4 \ -msse2 \ -mfpmath=sse \ + -mmmx \ + -m32 \ -fuse-ld=gold \ -ffunction-sections \ -funwind-tables \ @@ -172,6 +174,7 @@ MY_CFLAGS_Release := \ MY_DEFS_Release := \ '-DV8_DEPRECATION_WARNINGS' \ + '-DBLINK_SCALE_FILTERS_AT_RECORD_TIME' \ '-D_FILE_OFFSET_BITS=64' \ '-DNO_TCMALLOC' \ '-DDISABLE_NACL' \ @@ -179,14 +182,15 @@ MY_DEFS_Release := \ '-DUSE_LIBJPEG_TURBO=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ + '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ - '-DUSE_OPENSSL=1' \ '-DENABLE_EGLIMAGE=1' \ '-DCLD_VERSION=1' \ '-DENABLE_PRINTING=1' \ '-DENABLE_MANAGED_USERS=1' \ '-DGIN_IMPLEMENTATION' \ + '-DUSE_OPENSSL=1' \ '-D__STDC_CONSTANT_MACROS' \ '-D__STDC_FORMAT_MACROS' \ '-DANDROID' \ @@ -225,9 +229,11 @@ LOCAL_CPPFLAGS_Release := \ LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION)) LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION)) LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION)) +LOCAL_ASFLAGS := $(LOCAL_CFLAGS) ### Rules for final target. LOCAL_LDFLAGS_Debug := \ + -Wl,--fatal-warnings \ -Wl,-z,now \ -Wl,-z,relro \ -Wl,-z,noexecstack \ @@ -237,7 +243,6 @@ LOCAL_LDFLAGS_Debug := \ -nostdlib \ -Wl,--no-undefined \ -Wl,--exclude-libs=ALL \ - -Wl,--fatal-warnings \ -Wl,--gc-sections \ -Wl,--warn-shared-textrel \ -Wl,-O1 \ @@ -245,6 +250,7 @@ LOCAL_LDFLAGS_Debug := \ LOCAL_LDFLAGS_Release := \ + -Wl,--fatal-warnings \ -Wl,-z,now \ -Wl,-z,relro \ -Wl,-z,noexecstack \ @@ -257,7 +263,6 @@ LOCAL_LDFLAGS_Release := \ -Wl,-O1 \ -Wl,--as-needed \ -Wl,--gc-sections \ - -Wl,--fatal-warnings \ -Wl,--warn-shared-textrel diff --git a/gin/gin.target.linux-arm.mk b/gin/gin.target.linux-arm.mk index 9da148631c..6d6bee45f1 100644 --- a/gin/gin.target.linux-arm.mk +++ b/gin/gin.target.linux-arm.mk @@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \ gin/converter.cc \ gin/dictionary.cc \ gin/function_template.cc \ + gin/interceptor.cc \ gin/isolate_holder.cc \ gin/modules/console.cc \ gin/modules/file_module_provider.cc \ @@ -40,6 +41,7 @@ LOCAL_SRC_FILES := \ gin/per_context_data.cc \ gin/per_isolate_data.cc \ gin/runner.cc \ + gin/shell_runner.cc \ gin/try_catch.cc \ gin/wrappable.cc \ gin/wrapper_info.cc @@ -82,6 +84,7 @@ MY_CFLAGS_Debug := \ MY_DEFS_Debug := \ '-DV8_DEPRECATION_WARNINGS' \ + '-DBLINK_SCALE_FILTERS_AT_RECORD_TIME' \ '-D_FILE_OFFSET_BITS=64' \ '-DNO_TCMALLOC' \ '-DDISABLE_NACL' \ @@ -89,14 +92,15 @@ MY_DEFS_Debug := \ '-DUSE_LIBJPEG_TURBO=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ + '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ - '-DUSE_OPENSSL=1' \ '-DENABLE_EGLIMAGE=1' \ '-DCLD_VERSION=1' \ '-DENABLE_PRINTING=1' \ '-DENABLE_MANAGED_USERS=1' \ '-DGIN_IMPLEMENTATION' \ + '-DUSE_OPENSSL=1' \ '-D__STDC_CONSTANT_MACROS' \ '-D__STDC_FORMAT_MACROS' \ '-DANDROID' \ @@ -169,6 +173,7 @@ MY_CFLAGS_Release := \ MY_DEFS_Release := \ '-DV8_DEPRECATION_WARNINGS' \ + '-DBLINK_SCALE_FILTERS_AT_RECORD_TIME' \ '-D_FILE_OFFSET_BITS=64' \ '-DNO_TCMALLOC' \ '-DDISABLE_NACL' \ @@ -176,14 +181,15 @@ MY_DEFS_Release := \ '-DUSE_LIBJPEG_TURBO=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ + '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ - '-DUSE_OPENSSL=1' \ '-DENABLE_EGLIMAGE=1' \ '-DCLD_VERSION=1' \ '-DENABLE_PRINTING=1' \ '-DENABLE_MANAGED_USERS=1' \ '-DGIN_IMPLEMENTATION' \ + '-DUSE_OPENSSL=1' \ '-D__STDC_CONSTANT_MACROS' \ '-D__STDC_FORMAT_MACROS' \ '-DANDROID' \ @@ -223,9 +229,11 @@ LOCAL_CPPFLAGS_Release := \ LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION)) LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION)) LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION)) +LOCAL_ASFLAGS := $(LOCAL_CFLAGS) ### Rules for final target. LOCAL_LDFLAGS_Debug := \ + -Wl,--fatal-warnings \ -Wl,-z,now \ -Wl,-z,relro \ -Wl,-z,noexecstack \ @@ -237,7 +245,6 @@ LOCAL_LDFLAGS_Debug := \ -Wl,--no-undefined \ -Wl,--exclude-libs=ALL \ -Wl,--icf=safe \ - -Wl,--fatal-warnings \ -Wl,--gc-sections \ -Wl,--warn-shared-textrel \ -Wl,-O1 \ @@ -245,6 +252,7 @@ LOCAL_LDFLAGS_Debug := \ LOCAL_LDFLAGS_Release := \ + -Wl,--fatal-warnings \ -Wl,-z,now \ -Wl,-z,relro \ -Wl,-z,noexecstack \ @@ -259,7 +267,6 @@ LOCAL_LDFLAGS_Release := \ -Wl,-O1 \ -Wl,--as-needed \ -Wl,--gc-sections \ - -Wl,--fatal-warnings \ -Wl,--warn-shared-textrel diff --git a/gin/gin.target.linux-mips.mk b/gin/gin.target.linux-mips.mk index da8b23434c..1e1588ff47 100644 --- a/gin/gin.target.linux-mips.mk +++ b/gin/gin.target.linux-mips.mk @@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \ gin/converter.cc \ gin/dictionary.cc \ gin/function_template.cc \ + gin/interceptor.cc \ gin/isolate_holder.cc \ gin/modules/console.cc \ gin/modules/file_module_provider.cc \ @@ -40,6 +41,7 @@ LOCAL_SRC_FILES := \ gin/per_context_data.cc \ gin/per_isolate_data.cc \ gin/runner.cc \ + gin/shell_runner.cc \ gin/try_catch.cc \ gin/wrappable.cc \ gin/wrapper_info.cc @@ -81,6 +83,7 @@ MY_CFLAGS_Debug := \ MY_DEFS_Debug := \ '-DV8_DEPRECATION_WARNINGS' \ + '-DBLINK_SCALE_FILTERS_AT_RECORD_TIME' \ '-D_FILE_OFFSET_BITS=64' \ '-DNO_TCMALLOC' \ '-DDISABLE_NACL' \ @@ -88,14 +91,15 @@ MY_DEFS_Debug := \ '-DUSE_LIBJPEG_TURBO=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ + '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ - '-DUSE_OPENSSL=1' \ '-DENABLE_EGLIMAGE=1' \ '-DCLD_VERSION=1' \ '-DENABLE_PRINTING=1' \ '-DENABLE_MANAGED_USERS=1' \ '-DGIN_IMPLEMENTATION' \ + '-DUSE_OPENSSL=1' \ '-D__STDC_CONSTANT_MACROS' \ '-D__STDC_FORMAT_MACROS' \ '-DANDROID' \ @@ -167,6 +171,7 @@ MY_CFLAGS_Release := \ MY_DEFS_Release := \ '-DV8_DEPRECATION_WARNINGS' \ + '-DBLINK_SCALE_FILTERS_AT_RECORD_TIME' \ '-D_FILE_OFFSET_BITS=64' \ '-DNO_TCMALLOC' \ '-DDISABLE_NACL' \ @@ -174,14 +179,15 @@ MY_DEFS_Release := \ '-DUSE_LIBJPEG_TURBO=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ + '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ - '-DUSE_OPENSSL=1' \ '-DENABLE_EGLIMAGE=1' \ '-DCLD_VERSION=1' \ '-DENABLE_PRINTING=1' \ '-DENABLE_MANAGED_USERS=1' \ '-DGIN_IMPLEMENTATION' \ + '-DUSE_OPENSSL=1' \ '-D__STDC_CONSTANT_MACROS' \ '-D__STDC_FORMAT_MACROS' \ '-DANDROID' \ @@ -221,9 +227,11 @@ LOCAL_CPPFLAGS_Release := \ LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION)) LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION)) LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION)) +LOCAL_ASFLAGS := $(LOCAL_CFLAGS) ### Rules for final target. LOCAL_LDFLAGS_Debug := \ + -Wl,--fatal-warnings \ -Wl,-z,now \ -Wl,-z,relro \ -Wl,-z,noexecstack \ @@ -233,7 +241,6 @@ LOCAL_LDFLAGS_Debug := \ -nostdlib \ -Wl,--no-undefined \ -Wl,--exclude-libs=ALL \ - -Wl,--fatal-warnings \ -Wl,--gc-sections \ -Wl,--warn-shared-textrel \ -Wl,-O1 \ @@ -241,6 +248,7 @@ LOCAL_LDFLAGS_Debug := \ LOCAL_LDFLAGS_Release := \ + -Wl,--fatal-warnings \ -Wl,-z,now \ -Wl,-z,relro \ -Wl,-z,noexecstack \ @@ -253,7 +261,6 @@ LOCAL_LDFLAGS_Release := \ -Wl,-O1 \ -Wl,--as-needed \ -Wl,--gc-sections \ - -Wl,--fatal-warnings \ -Wl,--warn-shared-textrel diff --git a/gin/gin.target.linux-x86.mk b/gin/gin.target.linux-x86.mk index f0d0cb4504..0e2450ca66 100644 --- a/gin/gin.target.linux-x86.mk +++ b/gin/gin.target.linux-x86.mk @@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \ gin/converter.cc \ gin/dictionary.cc \ gin/function_template.cc \ + gin/interceptor.cc \ gin/isolate_holder.cc \ gin/modules/console.cc \ gin/modules/file_module_provider.cc \ @@ -40,6 +41,7 @@ LOCAL_SRC_FILES := \ gin/per_context_data.cc \ gin/per_isolate_data.cc \ gin/runner.cc \ + gin/shell_runner.cc \ gin/try_catch.cc \ gin/wrappable.cc \ gin/wrapper_info.cc @@ -57,11 +59,10 @@ MY_CFLAGS_Debug := \ -fvisibility=hidden \ -pipe \ -fPIC \ - -m32 \ - -mmmx \ - -march=pentium4 \ -msse2 \ -mfpmath=sse \ + -mmmx \ + -m32 \ -fuse-ld=gold \ -ffunction-sections \ -funwind-tables \ @@ -84,6 +85,7 @@ MY_CFLAGS_Debug := \ MY_DEFS_Debug := \ '-DV8_DEPRECATION_WARNINGS' \ + '-DBLINK_SCALE_FILTERS_AT_RECORD_TIME' \ '-D_FILE_OFFSET_BITS=64' \ '-DNO_TCMALLOC' \ '-DDISABLE_NACL' \ @@ -91,14 +93,15 @@ MY_DEFS_Debug := \ '-DUSE_LIBJPEG_TURBO=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ + '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ - '-DUSE_OPENSSL=1' \ '-DENABLE_EGLIMAGE=1' \ '-DCLD_VERSION=1' \ '-DENABLE_PRINTING=1' \ '-DENABLE_MANAGED_USERS=1' \ '-DGIN_IMPLEMENTATION' \ + '-DUSE_OPENSSL=1' \ '-D__STDC_CONSTANT_MACROS' \ '-D__STDC_FORMAT_MACROS' \ '-DANDROID' \ @@ -145,11 +148,10 @@ MY_CFLAGS_Release := \ -fvisibility=hidden \ -pipe \ -fPIC \ - -m32 \ - -mmmx \ - -march=pentium4 \ -msse2 \ -mfpmath=sse \ + -mmmx \ + -m32 \ -fuse-ld=gold \ -ffunction-sections \ -funwind-tables \ @@ -172,6 +174,7 @@ MY_CFLAGS_Release := \ MY_DEFS_Release := \ '-DV8_DEPRECATION_WARNINGS' \ + '-DBLINK_SCALE_FILTERS_AT_RECORD_TIME' \ '-D_FILE_OFFSET_BITS=64' \ '-DNO_TCMALLOC' \ '-DDISABLE_NACL' \ @@ -179,14 +182,15 @@ MY_DEFS_Release := \ '-DUSE_LIBJPEG_TURBO=1' \ '-DUSE_PROPRIETARY_CODECS' \ '-DENABLE_CONFIGURATION_POLICY' \ + '-DENABLE_NEW_GAMEPAD_API=1' \ '-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \ '-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \ - '-DUSE_OPENSSL=1' \ '-DENABLE_EGLIMAGE=1' \ '-DCLD_VERSION=1' \ '-DENABLE_PRINTING=1' \ '-DENABLE_MANAGED_USERS=1' \ '-DGIN_IMPLEMENTATION' \ + '-DUSE_OPENSSL=1' \ '-D__STDC_CONSTANT_MACROS' \ '-D__STDC_FORMAT_MACROS' \ '-DANDROID' \ @@ -225,9 +229,11 @@ LOCAL_CPPFLAGS_Release := \ LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION)) LOCAL_C_INCLUDES := $(GYP_COPIED_SOURCE_ORIGIN_DIRS) $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION)) LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION)) +LOCAL_ASFLAGS := $(LOCAL_CFLAGS) ### Rules for final target. LOCAL_LDFLAGS_Debug := \ + -Wl,--fatal-warnings \ -Wl,-z,now \ -Wl,-z,relro \ -Wl,-z,noexecstack \ @@ -237,7 +243,6 @@ LOCAL_LDFLAGS_Debug := \ -nostdlib \ -Wl,--no-undefined \ -Wl,--exclude-libs=ALL \ - -Wl,--fatal-warnings \ -Wl,--gc-sections \ -Wl,--warn-shared-textrel \ -Wl,-O1 \ @@ -245,6 +250,7 @@ LOCAL_LDFLAGS_Debug := \ LOCAL_LDFLAGS_Release := \ + -Wl,--fatal-warnings \ -Wl,-z,now \ -Wl,-z,relro \ -Wl,-z,noexecstack \ @@ -257,7 +263,6 @@ LOCAL_LDFLAGS_Release := \ -Wl,-O1 \ -Wl,--as-needed \ -Wl,--gc-sections \ - -Wl,--fatal-warnings \ -Wl,--warn-shared-textrel diff --git a/gin/handle.h b/gin/handle.h index da1de347f2..01db6606f1 100644 --- a/gin/handle.h +++ b/gin/handle.h @@ -60,7 +60,10 @@ struct Converter<gin::Handle<T> > { // without having to write out the type of the object explicitly. template<typename T> gin::Handle<T> CreateHandle(v8::Isolate* isolate, T* object) { - return gin::Handle<T>(object->GetWrapper(isolate), object); + v8::Handle<v8::Object> wrapper = object->GetWrapper(isolate); + if (wrapper.IsEmpty()) + return gin::Handle<T>(); + return gin::Handle<T>(wrapper, object); } } // namespace gin diff --git a/gin/interceptor.cc b/gin/interceptor.cc new file mode 100644 index 0000000000..7efc32ee68 --- /dev/null +++ b/gin/interceptor.cc @@ -0,0 +1,64 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/interceptor.h" + +#include <map> + +#include "gin/per_isolate_data.h" + +namespace gin { + +NamedPropertyInterceptor::NamedPropertyInterceptor(v8::Isolate* isolate, + WrappableBase* base) + : isolate_(isolate), base_(base) { + PerIsolateData::From(isolate_)->SetNamedPropertyInterceptor(base_, this); +} + +NamedPropertyInterceptor::~NamedPropertyInterceptor() { + PerIsolateData::From(isolate_)->ClearNamedPropertyInterceptor(base_, this); +} + +v8::Local<v8::Value> NamedPropertyInterceptor::GetNamedProperty( + v8::Isolate* isolate, + const std::string& property) { + return v8::Local<v8::Value>(); +} + +void NamedPropertyInterceptor::SetNamedProperty(v8::Isolate* isolate, + const std::string& property, + v8::Local<v8::Value> value) {} + +std::vector<std::string> NamedPropertyInterceptor::EnumerateNamedProperties( + v8::Isolate* isolate) { + return std::vector<std::string>(); +} + +IndexedPropertyInterceptor::IndexedPropertyInterceptor(v8::Isolate* isolate, + WrappableBase* base) + : isolate_(isolate), base_(base) { + PerIsolateData::From(isolate_)->SetIndexedPropertyInterceptor(base_, this); +} + +IndexedPropertyInterceptor::~IndexedPropertyInterceptor() { + PerIsolateData::From(isolate_)->ClearIndexedPropertyInterceptor(base_, this); +} + +v8::Local<v8::Value> IndexedPropertyInterceptor::GetIndexedProperty( + v8::Isolate* isolate, + uint32_t index) { + return v8::Local<v8::Value>(); +} + +void IndexedPropertyInterceptor::SetIndexedProperty( + v8::Isolate* isolate, + uint32_t index, + v8::Local<v8::Value> value) {} + +std::vector<uint32_t> IndexedPropertyInterceptor::EnumerateIndexedProperties( + v8::Isolate* isolate) { + return std::vector<uint32_t>(); +} + +} // namespace gin diff --git a/gin/interceptor.h b/gin/interceptor.h new file mode 100644 index 0000000000..802929b837 --- /dev/null +++ b/gin/interceptor.h @@ -0,0 +1,63 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_INTERCEPTOR_H_ +#define GIN_INTERCEPTOR_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "gin/gin_export.h" +#include "v8/include/v8.h" + +namespace gin { + +class WrappableBase; + +// Base class for gin::Wrappable-derived classes that want to implement a +// property interceptor. +class GIN_EXPORT NamedPropertyInterceptor { + public: + NamedPropertyInterceptor(v8::Isolate* isolate, WrappableBase* base); + virtual ~NamedPropertyInterceptor(); + + virtual v8::Local<v8::Value> GetNamedProperty(v8::Isolate* isolate, + const std::string& property); + virtual void SetNamedProperty(v8::Isolate* isolate, + const std::string& property, + v8::Local<v8::Value> value); + virtual std::vector<std::string> EnumerateNamedProperties( + v8::Isolate* isolate); + + private: + v8::Isolate* isolate_; + WrappableBase* base_; + + DISALLOW_COPY_AND_ASSIGN(NamedPropertyInterceptor); +}; + +class GIN_EXPORT IndexedPropertyInterceptor { + public: + IndexedPropertyInterceptor(v8::Isolate* isolate, WrappableBase* base); + virtual ~IndexedPropertyInterceptor(); + + virtual v8::Local<v8::Value> GetIndexedProperty(v8::Isolate* isolate, + uint32_t index); + virtual void SetIndexedProperty(v8::Isolate* isolate, + uint32_t index, + v8::Local<v8::Value> value); + virtual std::vector<uint32_t> EnumerateIndexedProperties( + v8::Isolate* isolate); + + private: + v8::Isolate* isolate_; + WrappableBase* base_; + + DISALLOW_COPY_AND_ASSIGN(IndexedPropertyInterceptor); +}; + +} // namespace gin + +#endif // GIN_INTERCEPTOR_H_ diff --git a/gin/interceptor_unittest.cc b/gin/interceptor_unittest.cc new file mode 100644 index 0000000000..ee6b7dc50a --- /dev/null +++ b/gin/interceptor_unittest.cc @@ -0,0 +1,159 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/logging.h" +#include "gin/arguments.h" +#include "gin/handle.h" +#include "gin/interceptor.h" +#include "gin/object_template_builder.h" +#include "gin/per_isolate_data.h" +#include "gin/public/isolate_holder.h" +#include "gin/test/v8_test.h" +#include "gin/try_catch.h" +#include "gin/wrappable.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gin { + +class MyInterceptor : public Wrappable<MyInterceptor>, + public NamedPropertyInterceptor, + public IndexedPropertyInterceptor { + public: + static WrapperInfo kWrapperInfo; + + static gin::Handle<MyInterceptor> Create(v8::Isolate* isolate) { + return CreateHandle(isolate, new MyInterceptor(isolate)); + } + + int value() const { return value_; } + void set_value(int value) { value_ = value; } + + // gin::NamedPropertyInterceptor + virtual v8::Local<v8::Value> GetNamedProperty(v8::Isolate* isolate, + const std::string& property) + OVERRIDE { + if (property == "value") { + return ConvertToV8(isolate, value_); + } else if (property == "func") { + return CreateFunctionTemplate(isolate, + base::Bind(&MyInterceptor::Call), + HolderIsFirstArgument)->GetFunction(); + } else { + return v8::Local<v8::Value>(); + } + } + virtual void SetNamedProperty(v8::Isolate* isolate, + const std::string& property, + v8::Local<v8::Value> value) OVERRIDE { + if (property != "value") + return; + ConvertFromV8(isolate, value, &value_); + } + virtual std::vector<std::string> EnumerateNamedProperties( + v8::Isolate* isolate) OVERRIDE { + std::vector<std::string> result; + result.push_back("func"); + result.push_back("value"); + return result; + } + + // gin::IndexedPropertyInterceptor + virtual v8::Local<v8::Value> GetIndexedProperty(v8::Isolate* isolate, + uint32_t index) OVERRIDE { + if (index == 0) + return ConvertToV8(isolate, value_); + return v8::Local<v8::Value>(); + } + virtual void SetIndexedProperty(v8::Isolate* isolate, + uint32_t index, + v8::Local<v8::Value> value) OVERRIDE { + if (index != 0) + return; + ConvertFromV8(isolate, value, &value_); + } + virtual std::vector<uint32_t> EnumerateIndexedProperties(v8::Isolate* isolate) + OVERRIDE { + std::vector<uint32_t> result; + result.push_back(0); + return result; + } + + private: + explicit MyInterceptor(v8::Isolate* isolate) + : NamedPropertyInterceptor(isolate, this), + IndexedPropertyInterceptor(isolate, this), + value_(0) {} + virtual ~MyInterceptor() {} + + // gin::Wrappable + virtual ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate* isolate) + OVERRIDE { + return Wrappable<MyInterceptor>::GetObjectTemplateBuilder(isolate) + .AddNamedPropertyInterceptor() + .AddIndexedPropertyInterceptor(); + } + + int Call(int value) { + int tmp = value_; + value_ = value; + return tmp; + } + + int value_; +}; + +WrapperInfo MyInterceptor::kWrapperInfo = {kEmbedderNativeGin}; + +class InterceptorTest : public V8Test { + public: + void RunInterceptorTest(const std::string& script_source) { + v8::Isolate* isolate = instance_->isolate(); + v8::HandleScope handle_scope(isolate); + + gin::Handle<MyInterceptor> obj = MyInterceptor::Create(isolate); + + obj->set_value(42); + EXPECT_EQ(42, obj->value()); + + v8::Handle<v8::String> source = StringToV8(isolate, script_source); + EXPECT_FALSE(source.IsEmpty()); + + gin::TryCatch try_catch; + v8::Handle<v8::Script> script = v8::Script::Compile(source); + EXPECT_FALSE(script.IsEmpty()); + v8::Handle<v8::Value> val = script->Run(); + EXPECT_FALSE(val.IsEmpty()); + v8::Handle<v8::Function> func; + EXPECT_TRUE(ConvertFromV8(isolate, val, &func)); + v8::Handle<v8::Value> argv[] = {ConvertToV8(isolate, obj.get()), }; + func->Call(v8::Undefined(isolate), 1, argv); + EXPECT_FALSE(try_catch.HasCaught()); + EXPECT_EQ("", try_catch.GetStackTrace()); + + EXPECT_EQ(191, obj->value()); + } +}; + +TEST_F(InterceptorTest, NamedInterceptor) { + RunInterceptorTest( + "(function (obj) {" + " if (obj.value !== 42) throw 'FAIL';" + " else obj.value = 191; })"); +} + +TEST_F(InterceptorTest, NamedInterceptorCall) { + RunInterceptorTest( + "(function (obj) {" + " if (obj.func(191) !== 42) throw 'FAIL';" + " })"); +} + +TEST_F(InterceptorTest, IndexedInterceptor) { + RunInterceptorTest( + "(function (obj) {" + " if (obj[0] !== 42) throw 'FAIL';" + " else obj[0] = 191; })"); +} + +} // namespace gin diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc index 411f26acec..bb243490dc 100644 --- a/gin/isolate_holder.cc +++ b/gin/isolate_holder.cc @@ -53,14 +53,14 @@ IsolateHolder::IsolateHolder() constraints.ConfigureDefaults(base::SysInfo::AmountOfPhysicalMemory(), base::SysInfo::NumberOfProcessors()); v8::SetResourceConstraints(isolate_, &constraints); - Init(); + Init(ArrayBufferAllocator::SharedInstance()); } -IsolateHolder::IsolateHolder(v8::Isolate* isolate) - : isolate_owner_(false), - isolate_(isolate) { +IsolateHolder::IsolateHolder(v8::Isolate* isolate, + v8::ArrayBuffer::Allocator* allocator) + : isolate_owner_(false), isolate_(isolate) { EnsureV8Initialized(false); - Init(); + Init(allocator); } IsolateHolder::~IsolateHolder() { @@ -69,10 +69,10 @@ IsolateHolder::~IsolateHolder() { isolate_->Dispose(); } -void IsolateHolder::Init() { +void IsolateHolder::Init(v8::ArrayBuffer::Allocator* allocator) { v8::Isolate::Scope isolate_scope(isolate_); v8::HandleScope handle_scope(isolate_); - isolate_data_.reset(new PerIsolateData(isolate_)); + isolate_data_.reset(new PerIsolateData(isolate_, allocator)); } } // namespace gin diff --git a/gin/modules/module_registry.cc b/gin/modules/module_registry.cc index eda34880e7..3712f1a41a 100644 --- a/gin/modules/module_registry.cc +++ b/gin/modules/module_registry.cc @@ -10,6 +10,8 @@ #include "base/logging.h" #include "gin/arguments.h" #include "gin/converter.h" +#include "gin/modules/module_registry_observer.h" +#include "gin/per_context_data.h" #include "gin/per_isolate_data.h" #include "gin/public/wrapper_info.h" #include "gin/runner.h" @@ -47,6 +49,13 @@ PendingModule::~PendingModule() { namespace { +// Key for base::SupportsUserData::Data. +const char kModuleRegistryKey[] = "ModuleRegistry"; + +struct ModuleRegistryData : public base::SupportsUserData::Data { + scoped_ptr<ModuleRegistry> registry; +}; + void Define(const v8::FunctionCallbackInfo<Value>& info) { Arguments args(info); @@ -87,10 +96,6 @@ Local<FunctionTemplate> GetDefineTemplate(Isolate* isolate) { return templ; } -v8::Handle<String> GetHiddenValueKey(Isolate* isolate) { - return StringToSymbol(isolate, "::gin::ModuleRegistry"); -} - } // namespace ModuleRegistry::ModuleRegistry(Isolate* isolate) @@ -101,26 +106,42 @@ ModuleRegistry::~ModuleRegistry() { modules_.Reset(); } +// static void ModuleRegistry::RegisterGlobals(Isolate* isolate, v8::Handle<ObjectTemplate> templ) { templ->Set(StringToSymbol(isolate, "define"), GetDefineTemplate(isolate)); } +// static +void ModuleRegistry::InstallGlobals(v8::Isolate* isolate, + v8::Handle<v8::Object> obj) { + obj->Set(StringToSymbol(isolate, "define"), + GetDefineTemplate(isolate)->GetFunction()); +} + +// static ModuleRegistry* ModuleRegistry::From(v8::Handle<Context> context) { - Isolate* isolate = context->GetIsolate(); - v8::Handle<String> key = GetHiddenValueKey(isolate); - v8::Handle<Value> value = context->Global()->GetHiddenValue(key); - v8::Handle<External> external; - if (value.IsEmpty() || !ConvertFromV8(isolate, value, &external)) { - PerContextData* data = PerContextData::From(context); - if (!data) - return NULL; - ModuleRegistry* registry = new ModuleRegistry(isolate); - context->Global()->SetHiddenValue(key, External::New(isolate, registry)); - data->AddSupplement(scoped_ptr<ContextSupplement>(registry)); - return registry; + PerContextData* data = PerContextData::From(context); + if (!data) + return NULL; + + ModuleRegistryData* registry_data = static_cast<ModuleRegistryData*>( + data->GetUserData(kModuleRegistryKey)); + if (!registry_data) { + // PerContextData takes ownership of ModuleRegistryData. + registry_data = new ModuleRegistryData; + registry_data->registry.reset(new ModuleRegistry(context->GetIsolate())); + data->SetUserData(kModuleRegistryKey, registry_data); } - return static_cast<ModuleRegistry*>(external->Value()); + return registry_data->registry.get(); +} + +void ModuleRegistry::AddObserver(ModuleRegistryObserver* observer) { + observer_list_.AddObserver(observer); +} + +void ModuleRegistry::RemoveObserver(ModuleRegistryObserver* observer) { + observer_list_.RemoveObserver(observer); } void ModuleRegistry::AddBuiltinModule(Isolate* isolate, const std::string& id, @@ -131,7 +152,11 @@ void ModuleRegistry::AddBuiltinModule(Isolate* isolate, const std::string& id, void ModuleRegistry::AddPendingModule(Isolate* isolate, scoped_ptr<PendingModule> pending) { + const std::string pending_id = pending->id; + const std::vector<std::string> pending_dependencies = pending->dependencies; AttemptToLoad(isolate, pending.Pass()); + FOR_EACH_OBSERVER(ModuleRegistryObserver, observer_list_, + OnDidAddPendingModule(pending_id, pending_dependencies)); } void ModuleRegistry::LoadModule(Isolate* isolate, @@ -168,11 +193,6 @@ void ModuleRegistry::RegisterModule(Isolate* isolate, callback.Run(module); } -void ModuleRegistry::Detach(v8::Handle<Context> context) { - context->Global()->SetHiddenValue(GetHiddenValueKey(context->GetIsolate()), - v8::Handle<Value>()); -} - bool ModuleRegistry::CheckDependencies(PendingModule* pending) { size_t num_missing_dependencies = 0; size_t len = pending->dependencies.size(); diff --git a/gin/modules/module_registry.h b/gin/modules/module_registry.h index 755875c353..5775a34a3d 100644 --- a/gin/modules/module_registry.h +++ b/gin/modules/module_registry.h @@ -13,11 +13,14 @@ #include "base/callback.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" +#include "base/observer_list.h" #include "gin/gin_export.h" -#include "gin/per_context_data.h" +#include "v8/include/v8.h" namespace gin { +class ModuleRegistryObserver; struct PendingModule; // This class implements the Asynchronous Module Definition (AMD) API. @@ -31,7 +34,7 @@ struct PendingModule; // function. The spec says we should only add that property once our // implementation complies with the specification. // -class GIN_EXPORT ModuleRegistry : public ContextSupplement { +class GIN_EXPORT ModuleRegistry { public: typedef base::Callback<void (v8::Handle<v8::Value>)> LoadModuleCallback; @@ -42,6 +45,13 @@ class GIN_EXPORT ModuleRegistry : public ContextSupplement { static void RegisterGlobals(v8::Isolate* isolate, v8::Handle<v8::ObjectTemplate> templ); + // Installs the necessary functions needed for modules. + // WARNING: this may execute script in the page. + static void InstallGlobals(v8::Isolate* isolate, v8::Handle<v8::Object> obj); + + void AddObserver(ModuleRegistryObserver* observer); + void RemoveObserver(ModuleRegistryObserver* observer); + // The caller must have already entered our context. void AddBuiltinModule(v8::Isolate* isolate, const std::string& id, v8::Handle<v8::Value> module); @@ -71,9 +81,6 @@ class GIN_EXPORT ModuleRegistry : public ContextSupplement { explicit ModuleRegistry(v8::Isolate* isolate); - // From ContextSupplement: - virtual void Detach(v8::Handle<v8::Context> context) OVERRIDE; - void Load(v8::Isolate* isolate, scoped_ptr<PendingModule> pending); void RegisterModule(v8::Isolate* isolate, const std::string& id, @@ -92,6 +99,8 @@ class GIN_EXPORT ModuleRegistry : public ContextSupplement { PendingModuleVector pending_modules_; v8::Persistent<v8::Object> modules_; + ObserverList<ModuleRegistryObserver> observer_list_; + DISALLOW_COPY_AND_ASSIGN(ModuleRegistry); }; diff --git a/gin/modules/module_registry_observer.h b/gin/modules/module_registry_observer.h new file mode 100644 index 0000000000..68ee4adc75 --- /dev/null +++ b/gin/modules/module_registry_observer.h @@ -0,0 +1,31 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_MODULES_MODULE_REGISTRY_OBSERVER_H_ +#define GIN_MODULES_MODULE_REGISTRY_OBSERVER_H_ + +#include <string> +#include <vector> + +#include "gin/gin_export.h" + +namespace gin { + +// Notified of interesting events from ModuleRegistry. +class GIN_EXPORT ModuleRegistryObserver { + public: + // Called from AddPendingModule(). |id| is the id/name of the module and + // |dependencies| this list of modules |id| depends upon. + virtual void OnDidAddPendingModule( + const std::string& id, + const std::vector<std::string>& dependencies) = 0; + + protected: + virtual ~ModuleRegistryObserver() {} +}; + +} // namespace gin + +#endif // GIN_MODULES_MODULE_REGISTRY_OBSERVER_H_ + diff --git a/gin/modules/module_registry_unittest.cc b/gin/modules/module_registry_unittest.cc new file mode 100644 index 0000000000..0ffdc0c3dd --- /dev/null +++ b/gin/modules/module_registry_unittest.cc @@ -0,0 +1,99 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/modules/module_registry.h" + +#include "base/message_loop/message_loop.h" +#include "gin/modules/module_registry_observer.h" +#include "gin/modules/module_runner_delegate.h" +#include "gin/public/context_holder.h" +#include "gin/public/isolate_holder.h" +#include "gin/shell_runner.h" +#include "gin/test/v8_test.h" +#include "v8/include/v8.h" + +namespace gin { + +namespace { + +struct TestHelper { + TestHelper(v8::Isolate* isolate) + : delegate(std::vector<base::FilePath>()), + runner(new ShellRunner(&delegate, isolate)), + scope(runner.get()) { + } + + base::MessageLoop message_loop; + ModuleRunnerDelegate delegate; + scoped_ptr<ShellRunner> runner; + Runner::Scope scope; +}; + +class ModuleRegistryObserverImpl : public ModuleRegistryObserver { + public: + ModuleRegistryObserverImpl() : did_add_count_(0) {} + + virtual void OnDidAddPendingModule( + const std::string& id, + const std::vector<std::string>& dependencies) OVERRIDE { + did_add_count_++; + id_ = id; + dependencies_ = dependencies; + } + + int did_add_count() { return did_add_count_; } + const std::string& id() const { return id_; } + const std::vector<std::string>& dependencies() const { return dependencies_; } + + private: + int did_add_count_; + std::string id_; + std::vector<std::string> dependencies_; + + DISALLOW_COPY_AND_ASSIGN(ModuleRegistryObserverImpl); +}; + +} // namespace + +typedef V8Test ModuleRegistryTest; + +// Verifies ModuleRegistry is not available after ContextHolder has been +// deleted. +TEST_F(ModuleRegistryTest, DestroyedWithContext) { + v8::Isolate::Scope isolate_scope(instance_->isolate()); + v8::HandleScope handle_scope(instance_->isolate()); + v8::Handle<v8::Context> context = v8::Context::New( + instance_->isolate(), NULL, v8::Handle<v8::ObjectTemplate>()); + { + ContextHolder context_holder(instance_->isolate()); + context_holder.SetContext(context); + ModuleRegistry* registry = ModuleRegistry::From(context); + EXPECT_TRUE(registry != NULL); + } + ModuleRegistry* registry = ModuleRegistry::From(context); + EXPECT_TRUE(registry == NULL); +} + +// Verifies ModuleRegistryObserver is notified appropriately. +TEST_F(ModuleRegistryTest, ModuleRegistryObserverTest) { + TestHelper helper(instance_->isolate()); + std::string source = + "define('id', ['dep1', 'dep2'], function() {" + " return function() {};" + "});"; + + ModuleRegistryObserverImpl observer; + ModuleRegistry::From(helper.runner->GetContextHolder()->context())-> + AddObserver(&observer); + helper.runner->Run(source, "script"); + ModuleRegistry::From(helper.runner->GetContextHolder()->context())-> + RemoveObserver(&observer); + EXPECT_EQ(1, observer.did_add_count()); + EXPECT_EQ("id", observer.id()); + ASSERT_EQ(2u, observer.dependencies().size()); + EXPECT_EQ("dep1", observer.dependencies()[0]); + EXPECT_EQ("dep2", observer.dependencies()[1]); +} + +} // namespace gin diff --git a/gin/modules/module_runner_delegate.cc b/gin/modules/module_runner_delegate.cc index 2a9f95cd76..16b5afd030 100644 --- a/gin/modules/module_runner_delegate.cc +++ b/gin/modules/module_runner_delegate.cc @@ -6,6 +6,7 @@ #include "gin/modules/module_registry.h" #include "gin/object_template_builder.h" +#include "gin/public/context_holder.h" namespace gin { @@ -23,34 +24,35 @@ void ModuleRunnerDelegate::AddBuiltinModule(const std::string& id, } void ModuleRunnerDelegate::AttemptToLoadMoreModules(Runner* runner) { - ModuleRegistry* registry = ModuleRegistry::From(runner->context()); - registry->AttemptToLoadMoreModules(runner->isolate()); + ModuleRegistry* registry = ModuleRegistry::From( + runner->GetContextHolder()->context()); + registry->AttemptToLoadMoreModules(runner->GetContextHolder()->isolate()); module_provider_.AttempToLoadModules( runner, registry->unsatisfied_dependencies()); } v8::Handle<v8::ObjectTemplate> ModuleRunnerDelegate::GetGlobalTemplate( - Runner* runner) { - v8::Handle<v8::ObjectTemplate> templ = - ObjectTemplateBuilder(runner->isolate()).Build(); - ModuleRegistry::RegisterGlobals(runner->isolate(), templ); + ShellRunner* runner, + v8::Isolate* isolate) { + v8::Handle<v8::ObjectTemplate> templ = ObjectTemplateBuilder(isolate).Build(); + ModuleRegistry::RegisterGlobals(isolate, templ); return templ; } -void ModuleRunnerDelegate::DidCreateContext(Runner* runner) { - RunnerDelegate::DidCreateContext(runner); +void ModuleRunnerDelegate::DidCreateContext(ShellRunner* runner) { + ShellRunnerDelegate::DidCreateContext(runner); - v8::Handle<v8::Context> context = runner->context(); + v8::Handle<v8::Context> context = runner->GetContextHolder()->context(); ModuleRegistry* registry = ModuleRegistry::From(context); + v8::Isolate* isolate = runner->GetContextHolder()->isolate(); for (BuiltinModuleMap::const_iterator it = builtin_modules_.begin(); it != builtin_modules_.end(); ++it) { - registry->AddBuiltinModule(runner->isolate(), it->first, - it->second(runner->isolate())); + registry->AddBuiltinModule(isolate, it->first, it->second(isolate)); } } -void ModuleRunnerDelegate::DidRunScript(Runner* runner) { +void ModuleRunnerDelegate::DidRunScript(ShellRunner* runner) { AttemptToLoadMoreModules(runner); } diff --git a/gin/modules/module_runner_delegate.h b/gin/modules/module_runner_delegate.h index 3ce056f250..09d4582dd7 100644 --- a/gin/modules/module_runner_delegate.h +++ b/gin/modules/module_runner_delegate.h @@ -10,7 +10,7 @@ #include "base/compiler_specific.h" #include "gin/gin_export.h" #include "gin/modules/file_module_provider.h" -#include "gin/runner.h" +#include "gin/shell_runner.h" namespace gin { @@ -19,7 +19,7 @@ typedef v8::Local<v8::Value> (*ModuleGetter)(v8::Isolate* isolate); // Emebedders that use AMD modules will probably want to use a RunnerDelegate // that inherits from ModuleRunnerDelegate. ModuleRunnerDelegate lets embedders // register built-in modules and routes module requests to FileModuleProvider. -class GIN_EXPORT ModuleRunnerDelegate : public RunnerDelegate { +class GIN_EXPORT ModuleRunnerDelegate : public ShellRunnerDelegate { public: explicit ModuleRunnerDelegate( const std::vector<base::FilePath>& search_paths); @@ -33,11 +33,12 @@ class GIN_EXPORT ModuleRunnerDelegate : public RunnerDelegate { private: typedef std::map<std::string, ModuleGetter> BuiltinModuleMap; - // From RunnerDelegate: + // From ShellRunnerDelegate: virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate( - Runner* runner) OVERRIDE; - virtual void DidCreateContext(Runner* runner) OVERRIDE; - virtual void DidRunScript(Runner* runner) OVERRIDE; + ShellRunner* runner, + v8::Isolate* isolate) OVERRIDE; + virtual void DidCreateContext(ShellRunner* runner) OVERRIDE; + virtual void DidRunScript(ShellRunner* runner) OVERRIDE; BuiltinModuleMap builtin_modules_; FileModuleProvider module_provider_; diff --git a/gin/modules/timer.cc b/gin/modules/timer.cc index 6d59f56cc3..3196dda425 100644 --- a/gin/modules/timer.cc +++ b/gin/modules/timer.cc @@ -45,8 +45,8 @@ Timer::Timer(v8::Isolate* isolate, bool repeating, int delay_ms, timer_(false, repeating), runner_(PerContextData::From( isolate->GetCurrentContext())->runner()->GetWeakPtr()) { - GetWrapper(runner_->isolate())->SetHiddenValue(GetHiddenPropertyName(isolate), - function); + GetWrapper(runner_->GetContextHolder()->isolate())->SetHiddenValue( + GetHiddenPropertyName(isolate), function); timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay_ms), base::Bind(&Timer::OnTimerFired, weak_factory_.GetWeakPtr())); } @@ -63,10 +63,10 @@ void Timer::OnTimerFired() { } Runner::Scope scope(runner_.get()); + v8::Isolate* isolate = runner_->GetContextHolder()->isolate(); v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast( - GetWrapper(runner_->isolate())->GetHiddenValue( - GetHiddenPropertyName(runner_->isolate()))); - runner_->Call(function, v8::Undefined(runner_->isolate()), 0, NULL); + GetWrapper(isolate)->GetHiddenValue(GetHiddenPropertyName(isolate))); + runner_->Call(function, v8::Undefined(isolate), 0, NULL); } diff --git a/gin/modules/timer_unittest.cc b/gin/modules/timer_unittest.cc index 9826747542..f7fd8f22e6 100644 --- a/gin/modules/timer_unittest.cc +++ b/gin/modules/timer_unittest.cc @@ -9,7 +9,7 @@ #include "gin/handle.h" #include "gin/object_template_builder.h" #include "gin/public/isolate_holder.h" -#include "gin/runner.h" +#include "gin/shell_runner.h" #include "gin/test/v8_test.h" #include "gin/try_catch.h" #include "gin/wrappable.h" @@ -54,7 +54,7 @@ WrapperInfo Result::kWrapperInfo = { gin::kEmbedderNativeGin }; struct TestHelper { TestHelper(v8::Isolate* isolate) - : runner(new Runner(&delegate, isolate)), + : runner(new ShellRunner(&delegate, isolate)), scope(runner.get()), timer_module(TimerModule::Create(isolate)), result(Result::Create(isolate)) { @@ -70,8 +70,8 @@ struct TestHelper { base::TimeDelta::FromMilliseconds(0)); } - RunnerDelegate delegate; - scoped_ptr<Runner> runner; + ShellRunnerDelegate delegate; + scoped_ptr<ShellRunner> runner; Runner::Scope scope; Handle<TimerModule> timer_module; Handle<Result> result; diff --git a/gin/object_template_builder.cc b/gin/object_template_builder.cc index 8bc271450a..603166cfab 100644 --- a/gin/object_template_builder.cc +++ b/gin/object_template_builder.cc @@ -3,10 +3,133 @@ // found in the LICENSE file. #include "gin/object_template_builder.h" + +#include "gin/interceptor.h" +#include "gin/per_isolate_data.h" #include "gin/public/wrapper_info.h" namespace gin { +namespace { + +WrappableBase* WrappableFromV8(v8::Isolate* isolate, + v8::Handle<v8::Value> val) { + if (!val->IsObject()) + return NULL; + v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(val); + WrapperInfo* info = WrapperInfo::From(obj); + + // If this fails, the object is not managed by Gin. + if (!info) + return NULL; + + // We don't further validate the type of the object, but assume it's derived + // from WrappableBase. We look up the pointer in a global registry, to make + // sure it's actually pointed to a valid life object. + return static_cast<WrappableBase*>( + obj->GetAlignedPointerFromInternalField(kEncodedValueIndex)); +} + +NamedPropertyInterceptor* NamedInterceptorFromV8(v8::Isolate* isolate, + v8::Handle<v8::Value> val) { + WrappableBase* base = WrappableFromV8(isolate, val); + if (!base) + return NULL; + return PerIsolateData::From(isolate)->GetNamedPropertyInterceptor(base); +} + +IndexedPropertyInterceptor* IndexedInterceptorFromV8( + v8::Isolate* isolate, + v8::Handle<v8::Value> val) { + WrappableBase* base = WrappableFromV8(isolate, val); + if (!base) + return NULL; + return PerIsolateData::From(isolate)->GetIndexedPropertyInterceptor(base); +} + +void NamedPropertyGetter(v8::Local<v8::String> property, + const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Isolate* isolate = info.GetIsolate(); + NamedPropertyInterceptor* interceptor = + NamedInterceptorFromV8(isolate, info.Holder()); + if (!interceptor) + return; + std::string name; + ConvertFromV8(isolate, property, &name); + info.GetReturnValue().Set(interceptor->GetNamedProperty(isolate, name)); +} + +void NamedPropertySetter(v8::Local<v8::String> property, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Isolate* isolate = info.GetIsolate(); + NamedPropertyInterceptor* interceptor = + NamedInterceptorFromV8(isolate, info.Holder()); + if (!interceptor) + return; + std::string name; + ConvertFromV8(isolate, property, &name); + interceptor->SetNamedProperty(isolate, name, value); +} + +void NamedPropertyQuery(v8::Local<v8::String> property, + const v8::PropertyCallbackInfo<v8::Integer>& info) { + v8::Isolate* isolate = info.GetIsolate(); + NamedPropertyInterceptor* interceptor = + NamedInterceptorFromV8(isolate, info.Holder()); + if (!interceptor) + return; + std::string name; + ConvertFromV8(isolate, property, &name); + if (interceptor->GetNamedProperty(isolate, name).IsEmpty()) + return; + info.GetReturnValue().Set(0); +} + +void NamedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { + v8::Isolate* isolate = info.GetIsolate(); + NamedPropertyInterceptor* interceptor = + NamedInterceptorFromV8(isolate, info.Holder()); + if (!interceptor) + return; + info.GetReturnValue().Set(v8::Handle<v8::Array>::Cast( + ConvertToV8(isolate, interceptor->EnumerateNamedProperties(isolate)))); +} + +void IndexedPropertyGetter(uint32_t index, + const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Isolate* isolate = info.GetIsolate(); + IndexedPropertyInterceptor* interceptor = + IndexedInterceptorFromV8(isolate, info.Holder()); + if (!interceptor) + return; + info.GetReturnValue().Set(interceptor->GetIndexedProperty(isolate, index)); +} + +void IndexedPropertySetter(uint32_t index, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Isolate* isolate = info.GetIsolate(); + IndexedPropertyInterceptor* interceptor = + IndexedInterceptorFromV8(isolate, info.Holder()); + if (!interceptor) + return; + interceptor->SetIndexedProperty(isolate, index, value); +} + +void IndexedPropertyEnumerator( + const v8::PropertyCallbackInfo<v8::Array>& info) { + v8::Isolate* isolate = info.GetIsolate(); + IndexedPropertyInterceptor* interceptor = + IndexedInterceptorFromV8(isolate, info.Holder()); + if (!interceptor) + return; + info.GetReturnValue().Set(v8::Handle<v8::Array>::Cast( + ConvertToV8(isolate, interceptor->EnumerateIndexedProperties(isolate)))); +} + +} // namespace + ObjectTemplateBuilder::ObjectTemplateBuilder(v8::Isolate* isolate) : isolate_(isolate), template_(v8::ObjectTemplate::New(isolate)) { template_->SetInternalFieldCount(kNumberOfInternalFields); @@ -15,6 +138,24 @@ ObjectTemplateBuilder::ObjectTemplateBuilder(v8::Isolate* isolate) ObjectTemplateBuilder::~ObjectTemplateBuilder() { } +ObjectTemplateBuilder& ObjectTemplateBuilder::AddNamedPropertyInterceptor() { + template_->SetNamedPropertyHandler(&NamedPropertyGetter, + &NamedPropertySetter, + &NamedPropertyQuery, + NULL, + &NamedPropertyEnumerator); + return *this; +} + +ObjectTemplateBuilder& ObjectTemplateBuilder::AddIndexedPropertyInterceptor() { + template_->SetIndexedPropertyHandler(&IndexedPropertyGetter, + &IndexedPropertySetter, + NULL, + NULL, + &IndexedPropertyEnumerator); + return *this; +} + ObjectTemplateBuilder& ObjectTemplateBuilder::SetImpl( const base::StringPiece& name, v8::Handle<v8::Data> val) { template_->Set(StringToSymbol(isolate_, name), val); diff --git a/gin/object_template_builder.h b/gin/object_template_builder.h index 6367b71245..3d025a9deb 100644 --- a/gin/object_template_builder.h +++ b/gin/object_template_builder.h @@ -27,6 +27,11 @@ struct CallbackTraits { T callback) { return CreateFunctionTemplate(isolate, base::Bind(callback)); } + static void SetAsFunctionHandler(v8::Isolate* isolate, + v8::Local<v8::ObjectTemplate> tmpl, + T callback) { + CreateFunctionHandler(isolate, tmpl, base::Bind(callback)); + } }; // Specialization for base::Callback. @@ -36,6 +41,11 @@ struct CallbackTraits<base::Callback<T> > { v8::Isolate* isolate, const base::Callback<T>& callback) { return CreateFunctionTemplate(isolate, callback); } + static void SetAsFunctionHandler(v8::Isolate* isolate, + v8::Local<v8::ObjectTemplate> tmpl, + const base::Callback<T>& callback) { + CreateFunctionHandler(isolate, tmpl, callback); + } }; // Specialization for member function pointers. We need to handle this case @@ -50,6 +60,12 @@ struct CallbackTraits<T, typename base::enable_if< return CreateFunctionTemplate(isolate, base::Bind(callback), HolderIsFirstArgument); } + static void SetAsFunctionHandler(v8::Isolate* isolate, + v8::Local<v8::ObjectTemplate> tmpl, + T callback) { + CreateFunctionHandler( + isolate, tmpl, base::Bind(callback), HolderIsFirstArgument); + } }; // This specialization allows people to construct function templates directly if @@ -103,6 +119,13 @@ class GIN_EXPORT ObjectTemplateBuilder { CallbackTraits<T>::CreateTemplate(isolate_, getter), CallbackTraits<U>::CreateTemplate(isolate_, setter)); } + template<typename T> + ObjectTemplateBuilder& SetCallAsFunctionHandler(const T& callback) { + CallbackTraits<T>::SetAsFunctionHandler(isolate_, template_, callback); + return *this; + } + ObjectTemplateBuilder& AddNamedPropertyInterceptor(); + ObjectTemplateBuilder& AddIndexedPropertyInterceptor(); v8::Local<v8::ObjectTemplate> Build(); diff --git a/gin/per_context_data.cc b/gin/per_context_data.cc index 5183d00102..178c0d122c 100644 --- a/gin/per_context_data.cc +++ b/gin/per_context_data.cc @@ -10,43 +10,24 @@ namespace gin { -ContextSupplement::ContextSupplement() { -} - -ContextSupplement::~ContextSupplement() { -} - -PerContextData::PerContextData(v8::Handle<v8::Context> context) - : runner_(NULL) { +PerContextData::PerContextData(ContextHolder* context_holder, + v8::Handle<v8::Context> context) + : context_holder_(context_holder), + runner_(NULL) { context->SetAlignedPointerInEmbedderData( kPerContextDataStartIndex + kEmbedderNativeGin, this); } PerContextData::~PerContextData() { - DCHECK(supplements_.empty()); -} - -void PerContextData::Detach(v8::Handle<v8::Context> context) { - DCHECK(From(context) == this); - context->SetAlignedPointerInEmbedderData( + v8::HandleScope handle_scope(context_holder_->isolate()); + context_holder_->context()->SetAlignedPointerInEmbedderData( kPerContextDataStartIndex + kEmbedderNativeGin, NULL); - - SuplementVector supplements; - supplements.swap(supplements_); - - for (SuplementVector::iterator it = supplements.begin(); - it != supplements.end(); ++it) { - (*it)->Detach(context); - } } +// static PerContextData* PerContextData::From(v8::Handle<v8::Context> context) { return static_cast<PerContextData*>( context->GetAlignedPointerFromEmbedderData(kEncodedValueIndex)); } -void PerContextData::AddSupplement(scoped_ptr<ContextSupplement> supplement) { - supplements_.push_back(supplement.release()); -} - } // namespace gin diff --git a/gin/per_context_data.h b/gin/per_context_data.h index 3ad68d2d37..0d1165345d 100644 --- a/gin/per_context_data.h +++ b/gin/per_context_data.h @@ -6,53 +6,39 @@ #define GIN_PER_CONTEXT_DATA_H_ #include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/memory/scoped_vector.h" +#include "base/supports_user_data.h" #include "gin/gin_export.h" #include "v8/include/v8.h" namespace gin { +class ContextHolder; class Runner; -// Embedders can store additional per-context data by subclassing -// ContextSupplement. -class GIN_EXPORT ContextSupplement { - public: - ContextSupplement(); - virtual ~ContextSupplement(); - - // Detach will be called before ContextHolder disposes the v8::Context. - // Embedders should not interact with |context| after Detach has been called. - virtual void Detach(v8::Handle<v8::Context> context) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(ContextSupplement); -}; - // There is one instance of PerContextData per v8::Context managed by Gin. This -// class stores all the Gin-related data that varies per context. -class GIN_EXPORT PerContextData { +// class stores all the Gin-related data that varies per context. Arbitrary data +// can be associated with this class by way of the SupportsUserData methods. +// Instances of this class (and any associated user data) are destroyed before +// the associated v8::Context. +class GIN_EXPORT PerContextData : public base::SupportsUserData { public: - explicit PerContextData(v8::Handle<v8::Context> context); - ~PerContextData(); + PerContextData(ContextHolder* context_holder, + v8::Handle<v8::Context> context); + virtual ~PerContextData(); // Can return NULL after the ContextHolder has detached from context. - static PerContextData* From(v8::Handle<v8::Context>); - void Detach(v8::Handle<v8::Context> context); + static PerContextData* From(v8::Handle<v8::Context> context); // The Runner associated with this context. To execute script in this context, // please use the appropriate API on Runner. Runner* runner() const { return runner_; } void set_runner(Runner* runner) { runner_ = runner; } - void AddSupplement(scoped_ptr<ContextSupplement> supplement); + ContextHolder* context_holder() { return context_holder_; } private: - typedef ScopedVector<ContextSupplement> SuplementVector; - + ContextHolder* context_holder_; Runner* runner_; - SuplementVector supplements_; DISALLOW_COPY_AND_ASSIGN(PerContextData); }; diff --git a/gin/per_context_data_unittest.cc b/gin/per_context_data_unittest.cc new file mode 100644 index 0000000000..4d79587195 --- /dev/null +++ b/gin/per_context_data_unittest.cc @@ -0,0 +1,34 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/per_context_data.h" + +#include "gin/public/context_holder.h" +#include "gin/public/isolate_holder.h" +#include "gin/test/v8_test.h" +#include "v8/include/v8.h" + +namespace gin { + +typedef V8Test PerContextDataTest; + +// Verifies PerContextData can be looked up by context and that it is not +// available once ContextHolder is destroyed. +TEST_F(PerContextDataTest, LookupAndDestruction) { + v8::Isolate::Scope isolate_scope(instance_->isolate()); + v8::HandleScope handle_scope(instance_->isolate()); + v8::Handle<v8::Context> context = v8::Context::New( + instance_->isolate(), NULL, v8::Handle<v8::ObjectTemplate>()); + { + ContextHolder context_holder(instance_->isolate()); + context_holder.SetContext(context); + PerContextData* per_context_data = PerContextData::From(context); + EXPECT_TRUE(per_context_data != NULL); + EXPECT_EQ(&context_holder, per_context_data->context_holder()); + } + PerContextData* per_context_data = PerContextData::From(context); + EXPECT_TRUE(per_context_data == NULL); +} + +} // namespace gin diff --git a/gin/per_isolate_data.cc b/gin/per_isolate_data.cc index 6c2397ba50..b3f24abe00 100644 --- a/gin/per_isolate_data.cc +++ b/gin/per_isolate_data.cc @@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/logging.h" #include "gin/per_isolate_data.h" #include "gin/public/gin_embedders.h" +using v8::ArrayBuffer; using v8::Eternal; using v8::Isolate; using v8::Local; @@ -14,8 +16,9 @@ using v8::ObjectTemplate; namespace gin { -PerIsolateData::PerIsolateData(Isolate* isolate) - : isolate_(isolate) { +PerIsolateData::PerIsolateData(Isolate* isolate, + ArrayBuffer::Allocator* allocator) + : isolate_(isolate), allocator_(allocator) { isolate_->SetData(kEmbedderNativeGin, this); } @@ -53,4 +56,54 @@ v8::Local<v8::FunctionTemplate> PerIsolateData::GetFunctionTemplate( return it->second.Get(isolate_); } +void PerIsolateData::SetIndexedPropertyInterceptor( + WrappableBase* base, + IndexedPropertyInterceptor* interceptor) { + indexed_interceptors_[base] = interceptor; +} + +void PerIsolateData::SetNamedPropertyInterceptor( + WrappableBase* base, + NamedPropertyInterceptor* interceptor) { + named_interceptors_[base] = interceptor; +} + +void PerIsolateData::ClearIndexedPropertyInterceptor( + WrappableBase* base, + IndexedPropertyInterceptor* interceptor) { + IndexedPropertyInterceptorMap::iterator it = indexed_interceptors_.find(base); + if (it != indexed_interceptors_.end()) + indexed_interceptors_.erase(it); + else + NOTREACHED(); +} + +void PerIsolateData::ClearNamedPropertyInterceptor( + WrappableBase* base, + NamedPropertyInterceptor* interceptor) { + NamedPropertyInterceptorMap::iterator it = named_interceptors_.find(base); + if (it != named_interceptors_.end()) + named_interceptors_.erase(it); + else + NOTREACHED(); +} + +IndexedPropertyInterceptor* PerIsolateData::GetIndexedPropertyInterceptor( + WrappableBase* base) { + IndexedPropertyInterceptorMap::iterator it = indexed_interceptors_.find(base); + if (it != indexed_interceptors_.end()) + return it->second; + else + return NULL; +} + +NamedPropertyInterceptor* PerIsolateData::GetNamedPropertyInterceptor( + WrappableBase* base) { + NamedPropertyInterceptorMap::iterator it = named_interceptors_.find(base); + if (it != named_interceptors_.end()) + return it->second; + else + return NULL; +} + } // namespace gin diff --git a/gin/per_isolate_data.h b/gin/per_isolate_data.h index ed93545474..fbdbca7e0e 100644 --- a/gin/per_isolate_data.h +++ b/gin/per_isolate_data.h @@ -14,11 +14,15 @@ namespace gin { +class IndexedPropertyInterceptor; +class NamedPropertyInterceptor; +class WrappableBase; + // There is one instance of PerIsolateData per v8::Isolate managed by Gin. This // class stores all the Gin-related data that varies per isolate. class GIN_EXPORT PerIsolateData { public: - explicit PerIsolateData(v8::Isolate* isolate); + PerIsolateData(v8::Isolate* isolate, v8::ArrayBuffer::Allocator* allocator); ~PerIsolateData(); static PerIsolateData* From(v8::Isolate* isolate); @@ -38,19 +42,43 @@ class GIN_EXPORT PerIsolateData { v8::Local<v8::ObjectTemplate> GetObjectTemplate(WrapperInfo* info); v8::Local<v8::FunctionTemplate> GetFunctionTemplate(WrapperInfo* info); + // We maintain a map from Wrappable objects that derive from one of the + // interceptor interfaces to the interceptor interface pointers. + void SetIndexedPropertyInterceptor(WrappableBase* base, + IndexedPropertyInterceptor* interceptor); + void SetNamedPropertyInterceptor(WrappableBase* base, + NamedPropertyInterceptor* interceptor); + + void ClearIndexedPropertyInterceptor(WrappableBase* base, + IndexedPropertyInterceptor* interceptor); + void ClearNamedPropertyInterceptor(WrappableBase* base, + NamedPropertyInterceptor* interceptor); + + IndexedPropertyInterceptor* GetIndexedPropertyInterceptor( + WrappableBase* base); + NamedPropertyInterceptor* GetNamedPropertyInterceptor(WrappableBase* base); + v8::Isolate* isolate() { return isolate_; } + v8::ArrayBuffer::Allocator* allocator() { return allocator_; } private: typedef std::map< WrapperInfo*, v8::Eternal<v8::ObjectTemplate> > ObjectTemplateMap; typedef std::map< WrapperInfo*, v8::Eternal<v8::FunctionTemplate> > FunctionTemplateMap; + typedef std::map<WrappableBase*, IndexedPropertyInterceptor*> + IndexedPropertyInterceptorMap; + typedef std::map<WrappableBase*, NamedPropertyInterceptor*> + NamedPropertyInterceptorMap; // PerIsolateData doesn't actually own |isolate_|. Instead, the isolate is // owned by the IsolateHolder, which also owns the PerIsolateData. v8::Isolate* isolate_; + v8::ArrayBuffer::Allocator* allocator_; ObjectTemplateMap object_templates_; FunctionTemplateMap function_templates_; + IndexedPropertyInterceptorMap indexed_interceptors_; + NamedPropertyInterceptorMap named_interceptors_; DISALLOW_COPY_AND_ASSIGN(PerIsolateData); }; diff --git a/gin/public/context_holder.h b/gin/public/context_holder.h index f8f0c4727a..afbcf23d73 100644 --- a/gin/public/context_holder.h +++ b/gin/public/context_holder.h @@ -25,9 +25,7 @@ enum ContextEmbedderDataFields { class PerContextData; -// ContextHolder is a generic class for holding a v8::Context. Rather than -// using ContextHolder directly, most code should use a subclass of -// ContextHolder, such as Runner. +// ContextHolder is a generic class for holding a v8::Context. class GIN_EXPORT ContextHolder { public: explicit ContextHolder(v8::Isolate* isolate); diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h index d68e4d5a58..eebafa7bcf 100644 --- a/gin/public/isolate_holder.h +++ b/gin/public/isolate_holder.h @@ -8,10 +8,7 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "gin/gin_export.h" - -namespace v8 { -class Isolate; -} +#include "v8/include/v8.h" namespace gin { @@ -30,14 +27,14 @@ class PerIsolateData; class GIN_EXPORT IsolateHolder { public: IsolateHolder(); - explicit IsolateHolder(v8::Isolate* isolate); + IsolateHolder(v8::Isolate* isolate, v8::ArrayBuffer::Allocator* allocator); ~IsolateHolder(); v8::Isolate* isolate() { return isolate_; } private: - void Init(); + void Init(v8::ArrayBuffer::Allocator* allocator); bool isolate_owner_; v8::Isolate* isolate_; diff --git a/gin/runner.cc b/gin/runner.cc index e8e4089d5f..6f018b165b 100644 --- a/gin/runner.cc +++ b/gin/runner.cc @@ -4,106 +4,18 @@ #include "gin/runner.h" -#include "gin/converter.h" -#include "gin/per_context_data.h" -#include "gin/try_catch.h" - -using v8::Context; -using v8::HandleScope; -using v8::Isolate; -using v8::Object; -using v8::ObjectTemplate; -using v8::Script; - namespace gin { -RunnerDelegate::RunnerDelegate() { -} - -RunnerDelegate::~RunnerDelegate() { -} - -v8::Handle<ObjectTemplate> RunnerDelegate::GetGlobalTemplate(Runner* runner) { - return v8::Handle<ObjectTemplate>(); -} - -void RunnerDelegate::DidCreateContext(Runner* runner) { -} - -void RunnerDelegate::WillRunScript(Runner* runner) { -} - -void RunnerDelegate::DidRunScript(Runner* runner) { -} - -void RunnerDelegate::UnhandledException(Runner* runner, TryCatch& try_catch) { - CHECK(false) << try_catch.GetStackTrace(); -} - -Runner::Runner(RunnerDelegate* delegate, Isolate* isolate) - : ContextHolder(isolate), - delegate_(delegate), - weak_factory_(this) { - v8::Isolate::Scope isolate_scope(isolate); - HandleScope handle_scope(isolate); - v8::Handle<v8::Context> context = - Context::New(isolate, NULL, delegate_->GetGlobalTemplate(this)); - - SetContext(context); - PerContextData::From(context)->set_runner(this); - - v8::Context::Scope scope(context); - delegate_->DidCreateContext(this); +Runner::Runner() : weak_factory_(this) { } Runner::~Runner() { } -void Runner::Run(const std::string& source, const std::string& resource_name) { - TryCatch try_catch; - v8::Handle<Script> script = Script::New(StringToV8(isolate(), source), - StringToV8(isolate(), resource_name)); - if (try_catch.HasCaught()) { - delegate_->UnhandledException(this, try_catch); - return; - } - - Run(script); -} - -void Runner::Run(v8::Handle<Script> script) { - TryCatch try_catch; - delegate_->WillRunScript(this); - - script->Run(); - - delegate_->DidRunScript(this); - if (try_catch.HasCaught()) { - delegate_->UnhandledException(this, try_catch); - } -} - -v8::Handle<v8::Value> Runner::Call(v8::Handle<v8::Function> function, - v8::Handle<v8::Value> receiver, - int argc, - v8::Handle<v8::Value> argv[]) { - TryCatch try_catch; - delegate_->WillRunScript(this); - - v8::Handle<v8::Value> result = function->Call(receiver, argc, argv); - - delegate_->DidRunScript(this); - if (try_catch.HasCaught()) { - delegate_->UnhandledException(this, try_catch); - } - - return result; -} - Runner::Scope::Scope(Runner* runner) - : isolate_scope_(runner->isolate()), - handle_scope_(runner->isolate()), - scope_(runner->context()) { + : isolate_scope_(runner->GetContextHolder()->isolate()), + handle_scope_(runner->GetContextHolder()->isolate()), + scope_(runner->GetContextHolder()->context()) { } Runner::Scope::~Scope() { diff --git a/gin/runner.h b/gin/runner.h index 943bcedba1..36a75d2f95 100644 --- a/gin/runner.h +++ b/gin/runner.h @@ -10,47 +10,28 @@ #include "base/memory/weak_ptr.h" #include "gin/gin_export.h" #include "gin/public/context_holder.h" +#include "v8/include/v8.h" namespace gin { -class Runner; -class TryCatch; - -// Subclass RunnerDelegate to customize the behavior of |Runner|. Typical -// embedders will want to subclass one of the specialized RunnerDelegates, -// such as ModuleRunnerDelegate. -class GIN_EXPORT RunnerDelegate { - public: - RunnerDelegate(); - virtual ~RunnerDelegate(); - - // Returns the template for the global object. - virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate(Runner* runner); - virtual void DidCreateContext(Runner* runner); - virtual void WillRunScript(Runner* runner); - virtual void DidRunScript(Runner* runner); - virtual void UnhandledException(Runner* runner, TryCatch& try_catch); -}; - -// Runner lets you run code in a v8::Context. Upon construction, Runner will -// create a v8::Context. Upon destruction, Runner will dispose the context. -class GIN_EXPORT Runner : public ContextHolder { +// Runner is responsible for running code in a v8::Context. +class GIN_EXPORT Runner { public: - Runner(RunnerDelegate* delegate, v8::Isolate* isolate); - ~Runner(); + Runner(); + virtual ~Runner(); // Before running script in this context, you'll need to enter the runner's // context by creating an instance of Runner::Scope on the stack. - void Run(const std::string& source, const std::string& resource_name); - void Run(v8::Handle<v8::Script> script); - - v8::Handle<v8::Value> Call(v8::Handle<v8::Function> function, - v8::Handle<v8::Value> receiver, - int argc, - v8::Handle<v8::Value> argv[]); - - v8::Handle<v8::Object> global() const { - return context()->Global(); + virtual void Run(const std::string& source, + const std::string& resource_name) = 0; + virtual v8::Handle<v8::Value> Call(v8::Handle<v8::Function> function, + v8::Handle<v8::Value> receiver, + int argc, + v8::Handle<v8::Value> argv[]) = 0; + virtual ContextHolder* GetContextHolder() = 0; + + v8::Handle<v8::Object> global() { + return GetContextHolder()->context()->Global(); } // Useful for running script in this context asynchronously. Rather than @@ -75,8 +56,6 @@ class GIN_EXPORT Runner : public ContextHolder { private: friend class Scope; - RunnerDelegate* delegate_; - base::WeakPtrFactory<Runner> weak_factory_; DISALLOW_COPY_AND_ASSIGN(Runner); diff --git a/gin/shell/gin_main.cc b/gin/shell/gin_main.cc index 0ff52cc229..6673b6a685 100644 --- a/gin/shell/gin_main.cc +++ b/gin/shell/gin_main.cc @@ -33,7 +33,7 @@ void Run(base::WeakPtr<Runner> runner, const base::FilePath& path) { std::vector<base::FilePath> GetModuleSearchPaths() { std::vector<base::FilePath> module_base(1); - CHECK(file_util::GetCurrentDirectory(&module_base[0])); + CHECK(base::GetCurrentDirectory(&module_base[0])); return module_base; } @@ -43,7 +43,7 @@ class ShellRunnerDelegate : public ModuleRunnerDelegate { AddBuiltinModule(Console::kModuleName, Console::GetModule); } - virtual void UnhandledException(Runner* runner, + virtual void UnhandledException(ShellRunner* runner, TryCatch& try_catch) OVERRIDE { ModuleRunnerDelegate::UnhandledException(runner, try_catch); LOG(ERROR) << try_catch.GetStackTrace(); @@ -66,7 +66,7 @@ int main(int argc, char** argv) { base::MessageLoop message_loop; gin::ShellRunnerDelegate delegate; - gin::Runner runner(&delegate, instance.isolate()); + gin::ShellRunner runner(&delegate, instance.isolate()); { gin::Runner::Scope scope(&runner); diff --git a/gin/shell_runner.cc b/gin/shell_runner.cc new file mode 100644 index 0000000000..8d98e425d7 --- /dev/null +++ b/gin/shell_runner.cc @@ -0,0 +1,112 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gin/shell_runner.h" + +#include "gin/converter.h" +#include "gin/modules/module_registry.h" +#include "gin/per_context_data.h" +#include "gin/public/context_holder.h" +#include "gin/try_catch.h" + +using v8::Context; +using v8::HandleScope; +using v8::Isolate; +using v8::Object; +using v8::ObjectTemplate; +using v8::Script; + +namespace gin { + +ShellRunnerDelegate::ShellRunnerDelegate() { +} + +ShellRunnerDelegate::~ShellRunnerDelegate() { +} + +v8::Handle<ObjectTemplate> ShellRunnerDelegate::GetGlobalTemplate( + ShellRunner* runner, + v8::Isolate* isolate) { + return v8::Handle<ObjectTemplate>(); +} + +void ShellRunnerDelegate::DidCreateContext(ShellRunner* runner) { +} + +void ShellRunnerDelegate::WillRunScript(ShellRunner* runner) { +} + +void ShellRunnerDelegate::DidRunScript(ShellRunner* runner) { +} + +void ShellRunnerDelegate::UnhandledException(ShellRunner* runner, + TryCatch& try_catch) { + CHECK(false) << try_catch.GetStackTrace(); +} + +ShellRunner::ShellRunner(ShellRunnerDelegate* delegate, Isolate* isolate) + : delegate_(delegate) { + v8::Isolate::Scope isolate_scope(isolate); + HandleScope handle_scope(isolate); + v8::Handle<v8::Context> context = + Context::New(isolate, NULL, delegate_->GetGlobalTemplate(this, isolate)); + + context_holder_.reset(new ContextHolder(isolate)); + context_holder_->SetContext(context); + PerContextData::From(context)->set_runner(this); + + v8::Context::Scope scope(context); + delegate_->DidCreateContext(this); +} + +ShellRunner::~ShellRunner() { +} + +void ShellRunner::Run(const std::string& source, + const std::string& resource_name) { + TryCatch try_catch; + v8::Isolate* isolate = GetContextHolder()->isolate(); + v8::Handle<Script> script = Script::Compile( + StringToV8(isolate, source), StringToV8(isolate, resource_name)); + if (try_catch.HasCaught()) { + delegate_->UnhandledException(this, try_catch); + return; + } + + Run(script); +} + +v8::Handle<v8::Value> ShellRunner::Call(v8::Handle<v8::Function> function, + v8::Handle<v8::Value> receiver, + int argc, + v8::Handle<v8::Value> argv[]) { + TryCatch try_catch; + delegate_->WillRunScript(this); + + v8::Handle<v8::Value> result = function->Call(receiver, argc, argv); + + delegate_->DidRunScript(this); + if (try_catch.HasCaught()) + delegate_->UnhandledException(this, try_catch); + + return result; +} + +ContextHolder* ShellRunner::GetContextHolder() { + return context_holder_.get(); +} + +void ShellRunner::Run(v8::Handle<Script> script) { + TryCatch try_catch; + delegate_->WillRunScript(this); + + script->Run(); + + delegate_->DidRunScript(this); + if (try_catch.HasCaught()) { + delegate_->UnhandledException(this, try_catch); + } +} + +} // namespace gin diff --git a/gin/shell_runner.h b/gin/shell_runner.h new file mode 100644 index 0000000000..645bc8e6df --- /dev/null +++ b/gin/shell_runner.h @@ -0,0 +1,68 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GIN_SHELL_RUNNER_H_ +#define GIN_SHELL_RUNNER_H_ + +#include "gin/runner.h" + +namespace gin { + +class ContextHolder; +class ShellRunner; +class TryCatch; + +// Subclass ShellRunnerDelegate to customize the behavior of ShellRunner. +// Typical embedders will want to subclass one of the specialized +// ShellRunnerDelegates, such as ModuleRunnerDelegate. +class GIN_EXPORT ShellRunnerDelegate { + public: + ShellRunnerDelegate(); + virtual ~ShellRunnerDelegate(); + + // Returns the template for the global object. + virtual v8::Handle<v8::ObjectTemplate> GetGlobalTemplate( + ShellRunner* runner, + v8::Isolate* isolate); + virtual void DidCreateContext(ShellRunner* runner); + virtual void WillRunScript(ShellRunner* runner); + virtual void DidRunScript(ShellRunner* runner); + virtual void UnhandledException(ShellRunner* runner, TryCatch& try_catch); +}; + +// ShellRunner executes the script/functions directly in a v8::Context. +// ShellRunner owns a ContextHolder and v8::Context, both of which are destroyed +// when the ShellRunner is deleted. +class GIN_EXPORT ShellRunner : public Runner { + public: + ShellRunner(ShellRunnerDelegate* delegate, v8::Isolate* isolate); + virtual ~ShellRunner(); + + // Before running script in this context, you'll need to enter the runner's + // context by creating an instance of Runner::Scope on the stack. + + // Runner overrides: + virtual void Run(const std::string& source, + const std::string& resource_name) OVERRIDE; + virtual v8::Handle<v8::Value> Call(v8::Handle<v8::Function> function, + v8::Handle<v8::Value> receiver, + int argc, + v8::Handle<v8::Value> argv[]) OVERRIDE; + virtual ContextHolder* GetContextHolder() OVERRIDE; + + private: + friend class Scope; + + void Run(v8::Handle<v8::Script> script); + + ShellRunnerDelegate* delegate_; + + scoped_ptr<ContextHolder> context_holder_; + + DISALLOW_COPY_AND_ASSIGN(ShellRunner); +}; + +} // namespace gin + +#endif // GIN_SHELL_RUNNER_H_ diff --git a/gin/runner_unittest.cc b/gin/shell_runner_unittest.cc index 3723956df6..93c071fc1e 100644 --- a/gin/runner_unittest.cc +++ b/gin/shell_runner_unittest.cc @@ -1,8 +1,8 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "gin/runner.h" +#include "gin/shell_runner.h" #include "base/compiler_specific.h" #include "gin/converter.h" @@ -21,9 +21,9 @@ TEST(RunnerTest, Run) { gin::IsolateHolder instance; - RunnerDelegate delegate; + ShellRunnerDelegate delegate; Isolate* isolate = instance.isolate(); - Runner runner(&delegate, isolate); + ShellRunner runner(&delegate, isolate); Runner::Scope scope(&runner); runner.Run(source, "test_data.js"); diff --git a/gin/test/file_runner.cc b/gin/test/file_runner.cc index 7b9127368d..86cb2f34b8 100644 --- a/gin/test/file_runner.cc +++ b/gin/test/file_runner.cc @@ -10,6 +10,7 @@ #include "gin/converter.h" #include "gin/modules/console.h" #include "gin/modules/module_registry.h" +#include "gin/public/context_holder.h" #include "gin/public/isolate_holder.h" #include "gin/test/gtest.h" #include "gin/try_catch.h" @@ -38,7 +39,7 @@ FileRunnerDelegate::FileRunnerDelegate() FileRunnerDelegate::~FileRunnerDelegate() { } -void FileRunnerDelegate::UnhandledException(Runner* runner, +void FileRunnerDelegate::UnhandledException(ShellRunner* runner, TryCatch& try_catch) { ModuleRunnerDelegate::UnhandledException(runner, try_catch); FAIL() << try_catch.GetStackTrace(); @@ -53,7 +54,7 @@ void RunTestFromFile(const base::FilePath& path, FileRunnerDelegate* delegate, base::MessageLoop message_loop; gin::IsolateHolder instance; - gin::Runner runner(delegate, instance.isolate()); + gin::ShellRunner runner(delegate, instance.isolate()); { gin::Runner::Scope scope(&runner); v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); @@ -65,8 +66,8 @@ void RunTestFromFile(const base::FilePath& path, FileRunnerDelegate* delegate, message_loop.Run(); } - v8::Handle<v8::Value> result = runner.context()->Global()->Get( - StringToSymbol(runner.isolate(), "result")); + v8::Handle<v8::Value> result = runner.global()->Get( + StringToSymbol(runner.GetContextHolder()->isolate(), "result")); EXPECT_EQ("PASS", V8ToString(result)); } } diff --git a/gin/test/file_runner.h b/gin/test/file_runner.h index 267023d8f0..f248fb59fa 100644 --- a/gin/test/file_runner.h +++ b/gin/test/file_runner.h @@ -24,7 +24,8 @@ class FileRunnerDelegate : public ModuleRunnerDelegate { private: // From ModuleRunnerDelegate: - virtual void UnhandledException(Runner* runner, TryCatch& try_catch) OVERRIDE; + virtual void UnhandledException(ShellRunner* runner, + TryCatch& try_catch) OVERRIDE; DISALLOW_COPY_AND_ASSIGN(FileRunnerDelegate); }; diff --git a/gin/wrappable.cc b/gin/wrappable.cc index 8d41ce06c4..a330fefc8e 100644 --- a/gin/wrappable.cc +++ b/gin/wrappable.cc @@ -44,6 +44,14 @@ v8::Handle<v8::Object> WrappableBase::GetWrapperImpl(v8::Isolate* isolate, } CHECK_EQ(kNumberOfInternalFields, templ->InternalFieldCount()); v8::Handle<v8::Object> wrapper = templ->NewInstance(); + // |wrapper| may be empty in some extreme cases, e.g., when + // Object.prototype.constructor is overwritten. + if (wrapper.IsEmpty()) { + // The current wrappable object will be no longer managed by V8. Delete this + // now. + delete this; + return wrapper; + } wrapper->SetAlignedPointerInInternalField(kWrapperInfoIndex, info); wrapper->SetAlignedPointerInInternalField(kEncodedValueIndex, this); wrapper_.Reset(isolate, wrapper); diff --git a/gin/wrappable_unittest.cc b/gin/wrappable_unittest.cc index 09fef241ab..4916153be5 100644 --- a/gin/wrappable_unittest.cc +++ b/gin/wrappable_unittest.cc @@ -74,6 +74,36 @@ class MyObjectSubclass : public MyObject { } }; +class MyCallableObject : public Wrappable<MyCallableObject> { + public: + static WrapperInfo kWrapperInfo; + + static gin::Handle<MyCallableObject> Create(v8::Isolate* isolate) { + return CreateHandle(isolate, new MyCallableObject()); + } + + int result() { return result_; } + + private: + virtual ObjectTemplateBuilder GetObjectTemplateBuilder( + v8::Isolate* isolate) OVERRIDE { + return Wrappable<MyCallableObject>::GetObjectTemplateBuilder(isolate) + .SetCallAsFunctionHandler(&MyCallableObject::Call); + } + + MyCallableObject() : result_(0) { + } + + virtual ~MyCallableObject() { + } + + void Call(int val) { + result_ = val; + } + + int result_; +}; + class MyObject2 : public Wrappable<MyObject2> { public: static WrapperInfo kWrapperInfo; @@ -90,6 +120,7 @@ ObjectTemplateBuilder MyObject::GetObjectTemplateBuilder(v8::Isolate* isolate) { .SetProperty("value", &MyObject::value, &MyObject::set_value); } +WrapperInfo MyCallableObject::kWrapperInfo = { kEmbedderNativeGin }; WrapperInfo MyObject2::kWrapperInfo = { kEmbedderNativeGin }; WrapperInfo MyObjectBlink::kWrapperInfo = { kEmbedderNativeGin }; @@ -153,7 +184,7 @@ TEST_F(WrappableTest, GetAndSetProperty) { EXPECT_FALSE(source.IsEmpty()); gin::TryCatch try_catch; - v8::Handle<v8::Script> script = v8::Script::New(source); + v8::Handle<v8::Script> script = v8::Script::Compile(source); EXPECT_FALSE(script.IsEmpty()); v8::Handle<v8::Value> val = script->Run(); EXPECT_FALSE(val.IsEmpty()); @@ -179,7 +210,7 @@ TEST_F(WrappableTest, WrappableSubclass) { "obj.sayHello('Lily');" "})"); gin::TryCatch try_catch; - v8::Handle<v8::Script> script = v8::Script::New(source); + v8::Handle<v8::Script> script = v8::Script::Compile(source); v8::Handle<v8::Value> val = script->Run(); v8::Handle<v8::Function> func; EXPECT_TRUE(ConvertFromV8(isolate, val, &func)); @@ -191,4 +222,49 @@ TEST_F(WrappableTest, WrappableSubclass) { EXPECT_EQ("Hello, Lily", object->result); } +TEST_F(WrappableTest, ErrorInObjectConstructorProperty) { + v8::Isolate* isolate = instance_->isolate(); + v8::HandleScope handle_scope(isolate); + + v8::Handle<v8::String> source = StringToV8( + isolate, + "(function() {" + " Object.defineProperty(Object.prototype, 'constructor', {" + " get: function() { throw 'Error'; }," + " set: function() { throw 'Error'; }" + " });" + "})();"); + EXPECT_FALSE(source.IsEmpty()); + v8::Handle<v8::Script> script = v8::Script::Compile(source); + script->Run(); + + gin::TryCatch try_catch; + gin::Handle<MyObject> obj = MyObject::Create(isolate); + EXPECT_TRUE(obj.IsEmpty()); + EXPECT_TRUE(try_catch.HasCaught()); +} + +TEST_F(WrappableTest, CallAsFunction) { + v8::Isolate* isolate = instance_->isolate(); + v8::HandleScope handle_scope(isolate); + + gin::Handle<MyCallableObject> object(MyCallableObject::Create(isolate)); + EXPECT_EQ(0, object->result()); + v8::Handle<v8::String> source = StringToV8(isolate, + "(function(obj) {" + "obj(42);" + "})"); + gin::TryCatch try_catch; + v8::Handle<v8::Script> script = v8::Script::Compile(source); + v8::Handle<v8::Value> val = script->Run(); + v8::Handle<v8::Function> func; + EXPECT_TRUE(ConvertFromV8(isolate, val, &func)); + v8::Handle<v8::Value> argv[] = { + ConvertToV8(isolate, object.get()) + }; + func->Call(v8::Undefined(isolate), 1, argv); + EXPECT_FALSE(try_catch.HasCaught()); + EXPECT_EQ(42, object->result()); +} + } // namespace gin |