From 8c2c7bb8a9bdc7a8c6a0f8a82b68ee33810c7a85 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Thu, 8 Sep 2011 18:42:44 +0700 Subject: [PATCH] vm context with accessors fixes #1673 --- src/node_script.cc | 59 ++++++++++++------- .../test-vm-create-context-accessors.js | 26 ++++++++ 2 files changed, 63 insertions(+), 22 deletions(-) create mode 100644 test/simple/test-vm-create-context-accessors.js diff --git a/src/node_script.cc b/src/node_script.cc index 4f4153caa98..79f93fec341 100644 --- a/src/node_script.cc +++ b/src/node_script.cc @@ -37,9 +37,11 @@ using v8::TryCatch; using v8::String; using v8::Exception; using v8::Local; +using v8::Null; using v8::Array; using v8::Persistent; using v8::Integer; +using v8::Function; using v8::FunctionTemplate; @@ -98,6 +100,38 @@ class WrappedScript : ObjectWrap { }; +Persistent cloneObjectMethod; + +void CloneObject(Handle recv, + Handle source, Handle target) { + HandleScope scope; + + Handle args[] = {source, target}; + + // Init + if (cloneObjectMethod.IsEmpty()) { + Local cloneObjectMethod_ = Local::Cast( + Script::Compile(String::New( + "(function(source, target) {\n\ + Object.getOwnPropertyNames(source).forEach(function(key) {\n\ + try {\n\ + var desc = Object.getOwnPropertyDescriptor(source, key);\n\ + if (desc.value === source) desc.value = target;\n\ + Object.defineProperty(target, key, desc);\n\ + } catch (e) {\n\ + // Catch sealed properties errors\n\ + }\n\ + });\n\ + })" + ), String::New("binding:script"))->Run() + ); + cloneObjectMethod = Persistent::New(cloneObjectMethod_); + } + + cloneObjectMethod->Call(recv, 2, args); +} + + void WrappedContext::Initialize(Handle target) { HandleScope scope; @@ -225,14 +259,8 @@ Handle WrappedScript::CreateContext(const Arguments& args) { if (args.Length() > 0) { Local sandbox = args[0]->ToObject(); - Local keys = sandbox->GetPropertyNames(); - for (uint32_t i = 0; i < keys->Length(); i++) { - Handle key = keys->Get(Integer::New(i))->ToString(); - Handle value = sandbox->Get(key); - if(value == sandbox) { value = context; } - context->Set(key, value); - } + CloneObject(args.This(), sandbox, context); } @@ -343,14 +371,7 @@ Handle WrappedScript::EvalMachine(const Arguments& args) { // Copy everything from the passed in sandbox (either the persistent // context for runInContext(), or the sandbox arg to runInNewContext()). - keys = sandbox->GetPropertyNames(); - - for (i = 0; i < keys->Length(); i++) { - Handle key = keys->Get(Integer::New(i))->ToString(); - Handle value = sandbox->Get(key); - if (value == sandbox) { value = context->Global(); } - context->Global()->Set(key, value); - } + CloneObject(args.This(), sandbox, context->Global()->GetPrototype()); } // Catch errors @@ -408,13 +429,7 @@ Handle WrappedScript::EvalMachine(const Arguments& args) { if (context_flag == userContext || context_flag == newContext) { // success! copy changes back onto the sandbox object. - keys = context->Global()->GetPropertyNames(); - for (i = 0; i < keys->Length(); i++) { - Handle key = keys->Get(Integer::New(i))->ToString(); - Handle value = context->Global()->Get(key); - if (value == context->Global()) { value = sandbox; } - sandbox->Set(key, value); - } + CloneObject(args.This(), context->Global()->GetPrototype(), sandbox); } if (context_flag == newContext) { diff --git a/test/simple/test-vm-create-context-accessors.js b/test/simple/test-vm-create-context-accessors.js new file mode 100644 index 00000000000..23fc935389d --- /dev/null +++ b/test/simple/test-vm-create-context-accessors.js @@ -0,0 +1,26 @@ +var common = require('../common'); +var assert = require('assert'); +var vm = require('vm'); + +var ctx = {}; + +Object.defineProperty(ctx, 'getter', { + get: function() { + return 'ok'; + } +}); + +var val; +Object.defineProperty(ctx, 'setter', { + set: function(_val) { + val = _val; + }, + get: function() { + return 'ok=' + val; + } +}); + +ctx = vm.createContext(ctx); + +var result = vm.runInContext('setter = "test";[getter,setter]', ctx); +assert.deepEqual(result, ['ok', 'ok=test']);