vm context with accessors
authorFedor Indutny <fedor.indutny@gmail.com>
Thu, 8 Sep 2011 11:42:44 +0000 (18:42 +0700)
committerRyan Dahl <ry@tinyclouds.org>
Sat, 10 Sep 2011 17:51:58 +0000 (10:51 -0700)
fixes #1673

src/node_script.cc
test/simple/test-vm-create-context-accessors.js [new file with mode: 0644]

index 4f4153c..79f93fe 100644 (file)
@@ -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<Function> cloneObjectMethod;
+
+void CloneObject(Handle<Object> recv,
+                 Handle<Value> source, Handle<Value> target) {
+  HandleScope scope;
+
+  Handle<Value> args[] = {source, target};
+
+  // Init
+  if (cloneObjectMethod.IsEmpty()) {
+    Local<Function> cloneObjectMethod_ = Local<Function>::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<Function>::New(cloneObjectMethod_);
+  }
+
+  cloneObjectMethod->Call(recv, 2, args);
+}
+
+
 void WrappedContext::Initialize(Handle<Object> target) {
   HandleScope scope;
 
@@ -225,14 +259,8 @@ Handle<Value> WrappedScript::CreateContext(const Arguments& args) {
 
   if (args.Length() > 0) {
     Local<Object> sandbox = args[0]->ToObject();
-    Local<Array> keys = sandbox->GetPropertyNames();
 
-    for (uint32_t i = 0; i < keys->Length(); i++) {
-      Handle<String> key = keys->Get(Integer::New(i))->ToString();
-      Handle<Value> value = sandbox->Get(key);
-      if(value == sandbox) { value = context; }
-      context->Set(key, value);
-    }
+    CloneObject(args.This(), sandbox, context);
   }
 
 
@@ -343,14 +371,7 @@ Handle<Value> 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<String> key = keys->Get(Integer::New(i))->ToString();
-      Handle<Value> 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<Value> 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<String> key = keys->Get(Integer::New(i))->ToString();
-      Handle<Value> 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 (file)
index 0000000..23fc935
--- /dev/null
@@ -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']);