Revision: 7887
Author: [email protected]
Date: Fri May 13 03:58:25 2011
Log: A first skeleton for introducing Harmony proxies.
1) Add new type JSProxy for representing proxy objects.
Currently devoid of functionality, i.e., all properties are undefined.
2) Some rudimentary global $Proxy functions to create proxies.
Next step: Hook up getProperty and getOwnProperty handlers. Will probably
require introducing a new LookupResult type, which is a mixture of
INTERCEPTOR (handles any property) and CALLBACK (calls back to JS).
Can we unify this somehow?
TODO: Should probably rename existing Proxy type to something like
"Foreign", to avoid confusion.
Review URL: http://codereview.chromium.org/6932068
http://code.google.com/p/v8/source/detail?r=7887
Modified:
/branches/bleeding_edge/include/v8.h
/branches/bleeding_edge/src/bootstrapper.cc
/branches/bleeding_edge/src/factory.cc
/branches/bleeding_edge/src/factory.h
/branches/bleeding_edge/src/heap.cc
/branches/bleeding_edge/src/heap.h
/branches/bleeding_edge/src/ia32/frames-ia32.h
/branches/bleeding_edge/src/objects-debug.cc
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects-printer.cc
/branches/bleeding_edge/src/objects-visiting.cc
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/proxy.js
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/runtime.h
/branches/bleeding_edge/src/runtime.js
=======================================
--- /branches/bleeding_edge/include/v8.h Mon May 9 08:24:48 2011
+++ /branches/bleeding_edge/include/v8.h Fri May 13 03:58:25 2011
@@ -3682,7 +3682,7 @@
static const int kFullStringRepresentationMask = 0x07;
static const int kExternalTwoByteRepresentationTag = 0x02;
- static const int kJSObjectType = 0xa1;
+ static const int kJSObjectType = 0xa2;
static const int kFirstNonstringType = 0x80;
static const int kProxyType = 0x85;
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Fri May 6 02:05:44 2011
+++ /branches/bleeding_edge/src/bootstrapper.cc Fri May 13 03:58:25 2011
@@ -1638,10 +1638,12 @@
bool Genesis::InstallExperimentalNatives() {
- if (FLAG_harmony_proxies) {
- for (int i = ExperimentalNatives::GetDebuggerCount();
- i < ExperimentalNatives::GetBuiltinsCount();
- i++) {
+ for (int i = ExperimentalNatives::GetDebuggerCount();
+ i < ExperimentalNatives::GetBuiltinsCount();
+ i++) {
+ if (FLAG_harmony_proxies &&
+ strcmp(ExperimentalNatives::GetScriptName(i).start(),
+ "native proxy.js") == 0) {
if (!CompileExperimentalBuiltin(isolate(), i)) return false;
}
}
=======================================
--- /branches/bleeding_edge/src/factory.cc Wed Mar 23 06:40:07 2011
+++ /branches/bleeding_edge/src/factory.cc Fri May 13 03:58:25 2011
@@ -830,6 +830,15 @@
result->SetContent(*elements);
return result;
}
+
+
+Handle<JSProxy> Factory::NewJSProxy(Handle<Object> handler,
+ Handle<Object> prototype) {
+ CALL_HEAP_FUNCTION(
+ isolate(),
+ isolate()->heap()->AllocateJSProxy(*handler, *prototype),
+ JSProxy);
+}
Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
=======================================
--- /branches/bleeding_edge/src/factory.h Wed Mar 23 02:57:12 2011
+++ /branches/bleeding_edge/src/factory.h Fri May 13 03:58:25 2011
@@ -231,6 +231,8 @@
Handle<FixedArray> elements,
PretenureFlag pretenure = NOT_TENURED);
+ Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object>
prototype);
+
Handle<JSFunction> NewFunction(Handle<String> name,
Handle<Object> prototype);
=======================================
--- /branches/bleeding_edge/src/heap.cc Fri May 13 00:26:44 2011
+++ /branches/bleeding_edge/src/heap.cc Fri May 13 03:58:25 2011
@@ -3211,6 +3211,27 @@
#endif
return result;
}
+
+
+MaybeObject* Heap::AllocateJSProxy(Object* handler, Object* prototype) {
+ // Allocate map.
+ // TODO(rossberg): Once we optimize proxies, think about a scheme to
share
+ // maps. Will probably depend on the identity of the handler object, too.
+ Object* map_obj;
+ MaybeObject* maybe_map_obj = AllocateMap(JS_PROXY_TYPE, JSProxy::kSize);
+ if (!maybe_map_obj->ToObject(&map_obj)) return maybe_map_obj;
+ Map* map = Map::cast(map_obj);
+ map->set_prototype(prototype);
+ map->set_pre_allocated_property_fields(1);
+ map->set_inobject_properties(1);
+
+ // Allocate the proxy object.
+ Object* result;
+ MaybeObject* maybe_result = Allocate(map, NEW_SPACE);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ JSProxy::cast(result)->set_handler(handler);
+ return result;
+}
MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
=======================================
--- /branches/bleeding_edge/src/heap.h Tue May 10 23:39:27 2011
+++ /branches/bleeding_edge/src/heap.h Fri May 13 03:58:25 2011
@@ -452,6 +452,13 @@
// Please note this does not perform a garbage collection.
MUST_USE_RESULT MaybeObject* AllocateFunctionPrototype(JSFunction*
function);
+ // Allocates a Harmony Proxy.
+ // Returns Failure::RetryAfterGC(requested_bytes, space) if the
allocation
+ // failed.
+ // Please note this does not perform a garbage collection.
+ MUST_USE_RESULT MaybeObject* AllocateJSProxy(Object* handler,
+ Object* prototype);
+
// Reinitialize an JSGlobalProxy based on a constructor. The object
// must have the same size as objects allocated using the
// constructor. The object is reinitialized and behaves as an
=======================================
--- /branches/bleeding_edge/src/ia32/frames-ia32.h Fri Apr 1 04:41:36 2011
+++ /branches/bleeding_edge/src/ia32/frames-ia32.h Fri May 13 03:58:25 2011
@@ -80,8 +80,8 @@
class ExitFrameConstants : public AllStatic {
public:
- static const int kCodeOffset = -2 * kPointerSize;
- static const int kSPOffset = -1 * kPointerSize;
+ static const int kCodeOffset = -2 * kPointerSize;
+ static const int kSPOffset = -1 * kPointerSize;
static const int kCallerFPOffset = 0 * kPointerSize;
static const int kCallerPCOffset = +1 * kPointerSize;
@@ -94,7 +94,9 @@
class StandardFrameConstants : public AllStatic {
public:
- static const int kFixedFrameSize = 4;
+ // StandardFrame::IterateExpressions assumes that kContextOffset is the
last
+ // object pointer.
+ static const int kFixedFrameSize = 4; // Currently unused.
static const int kExpressionsOffset = -3 * kPointerSize;
static const int kMarkerOffset = -2 * kPointerSize;
static const int kContextOffset = -1 * kPointerSize;
=======================================
--- /branches/bleeding_edge/src/objects-debug.cc Thu Apr 21 00:15:43 2011
+++ /branches/bleeding_edge/src/objects-debug.cc Fri May 13 03:58:25 2011
@@ -155,6 +155,9 @@
break;
case FILLER_TYPE:
break;
+ case JS_PROXY_TYPE:
+ JSProxy::cast(this)->JSProxyVerify();
+ break;
case PROXY_TYPE:
Proxy::cast(this)->ProxyVerify();
break;
@@ -461,6 +464,11 @@
}
+void JSProxy::JSProxyVerify() {
+ ASSERT(IsJSProxy());
+ VerifyPointer(handler());
+}
+
void Proxy::ProxyVerify() {
ASSERT(IsProxy());
}
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Fri May 13 00:26:44 2011
+++ /branches/bleeding_edge/src/objects-inl.h Fri May 13 03:58:25 2011
@@ -582,6 +582,12 @@
bool Object::IsStringWrapper() {
return IsJSValue() && JSValue::cast(this)->value()->IsString();
}
+
+
+bool Object::IsJSProxy() {
+ return Object::IsHeapObject()
+ && HeapObject::cast(this)->map()->instance_type() == JS_PROXY_TYPE;
+}
bool Object::IsProxy() {
@@ -1898,6 +1904,7 @@
CAST_ACCESSOR(Code)
CAST_ACCESSOR(JSArray)
CAST_ACCESSOR(JSRegExp)
+CAST_ACCESSOR(JSProxy)
CAST_ACCESSOR(Proxy)
CAST_ACCESSOR(ByteArray)
CAST_ACCESSOR(ExternalArray)
@@ -3519,6 +3526,9 @@
WRITE_FIELD(this, OffsetOfCodeWithId(id), value);
ASSERT(!HEAP->InNewSpace(value));
}
+
+
+ACCESSORS(JSProxy, handler, Object, kHandlerOffset)
Address Proxy::proxy() {
=======================================
--- /branches/bleeding_edge/src/objects-printer.cc Tue May 10 07:17:23 2011
+++ /branches/bleeding_edge/src/objects-printer.cc Fri May 13 03:58:25 2011
@@ -148,6 +148,9 @@
case CODE_TYPE:
Code::cast(this)->CodePrint(out);
break;
+ case JS_PROXY_TYPE:
+ JSProxy::cast(this)->JSProxyPrint(out);
+ break;
case PROXY_TYPE:
Proxy::cast(this)->ProxyPrint(out);
break;
@@ -408,6 +411,7 @@
case JS_FUNCTION_TYPE: return "JS_FUNCTION";
case CODE_TYPE: return "CODE";
case JS_ARRAY_TYPE: return "JS_ARRAY";
+ case JS_PROXY_TYPE: return "JS_PROXY";
case JS_REGEXP_TYPE: return "JS_REGEXP";
case JS_VALUE_TYPE: return "JS_VALUE";
case JS_GLOBAL_OBJECT_TYPE: return "JS_GLOBAL_OBJECT";
@@ -528,6 +532,15 @@
if (!StringShape(this).IsSymbol()) PrintF(out, "\"");
}
+
+
+void JSProxy::JSProxyPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "JSProxy");
+ PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - handler = ");
+ handler()->Print(out);
+ PrintF(out, "\n");
+}
void JSFunction::JSFunctionPrint(FILE* out) {
=======================================
--- /branches/bleeding_edge/src/objects-visiting.cc Thu Apr 21 00:15:43 2011
+++ /branches/bleeding_edge/src/objects-visiting.cc Fri May 13 03:58:25 2011
@@ -88,6 +88,11 @@
case SHARED_FUNCTION_INFO_TYPE:
return kVisitSharedFunctionInfo;
+ case JS_PROXY_TYPE:
+ return GetVisitorIdForSize(kVisitDataObject,
+ kVisitDataObjectGeneric,
+ JSProxy::kSize);
+
case PROXY_TYPE:
return GetVisitorIdForSize(kVisitDataObject,
kVisitDataObjectGeneric,
=======================================
--- /branches/bleeding_edge/src/objects.cc Wed May 11 04:25:03 2011
+++ /branches/bleeding_edge/src/objects.cc Fri May 13 03:58:25 2011
@@ -134,24 +134,22 @@
void Object::Lookup(String* name, LookupResult* result) {
Object* holder = NULL;
if (IsSmi()) {
- Heap* heap = Isolate::Current()->heap();
- Context* global_context = heap->isolate()->context()->global_context();
+ Context* global_context =
Isolate::Current()->context()->global_context();
holder = global_context->number_function()->instance_prototype();
} else {
HeapObject* heap_object = HeapObject::cast(this);
if (heap_object->IsJSObject()) {
return JSObject::cast(this)->Lookup(name, result);
}
- Heap* heap = heap_object->GetHeap();
+ Context* global_context =
Isolate::Current()->context()->global_context();
if (heap_object->IsString()) {
- Context* global_context =
heap->isolate()->context()->global_context();
holder = global_context->string_function()->instance_prototype();
} else if (heap_object->IsHeapNumber()) {
- Context* global_context =
heap->isolate()->context()->global_context();
holder = global_context->number_function()->instance_prototype();
} else if (heap_object->IsBoolean()) {
- Context* global_context =
heap->isolate()->context()->global_context();
holder = global_context->boolean_function()->instance_prototype();
+ } else if (heap_object->IsJSProxy()) {
+ return result->NotFound(); // For now...
}
}
ASSERT(holder != NULL); // Cannot handle null or undefined.
@@ -494,12 +492,13 @@
Heap* heap = name->GetHeap();
// Traverse the prototype chain from the current object (this) to
- // the holder and check for access rights. This avoid traversing the
+ // the holder and check for access rights. This avoids traversing the
// objects more than once in case of interceptors, because the
// holder will always be the interceptor holder and the search may
// only continue with a current object just after the interceptor
// holder in the prototype chain.
Object* last = result->IsProperty() ? result->holder() :
heap->null_value();
+ ASSERT(this != this->GetPrototype());
for (Object* current = this; true; current = current->GetPrototype()) {
if (current->IsAccessCheckNeeded()) {
// Check if we're allowed to read from the current object. Note
@@ -575,6 +574,8 @@
holder = global_context->number_function()->instance_prototype();
} else if (heap_object->IsBoolean()) {
holder = global_context->boolean_function()->instance_prototype();
+ } else if (heap_object->IsJSProxy()) {
+ return heap->undefined_value(); // For now...
} else {
// Undefined and null have no indexed properties.
ASSERT(heap_object->IsUndefined() || heap_object->IsNull());
@@ -595,9 +596,10 @@
HeapObject* heap_object = HeapObject::cast(this);
- // The object is either a number, a string, a boolean, or a real JS
object.
- if (heap_object->IsJSObject()) {
- return JSObject::cast(this)->map()->prototype();
+ // The object is either a number, a string, a boolean,
+ // a real JS object, or a Harmony proxy.
+ if (heap_object->IsJSObject() || heap_object->IsJSProxy()) {
+ return heap_object->map()->prototype();
}
Heap* heap = heap_object->GetHeap();
Context* context = heap->isolate()->context()->global_context();
@@ -1154,6 +1156,9 @@
case ODDBALL_TYPE:
Oddball::BodyDescriptor::IterateBody(this, v);
break;
+ case JS_PROXY_TYPE:
+ JSProxy::BodyDescriptor::IterateBody(this, v);
+ break;
case PROXY_TYPE:
reinterpret_cast<Proxy*>(this)->ProxyIterateBody(v);
break;
=======================================
--- /branches/bleeding_edge/src/objects.h Fri May 13 00:26:44 2011
+++ /branches/bleeding_edge/src/objects.h Fri May 13 03:58:25 2011
@@ -90,6 +90,7 @@
// - Code
// - Map
// - Oddball
+// - JSProxy
// - Proxy
// - SharedFunctionInfo
// - Struct
@@ -287,6 +288,7 @@
V(JS_GLOBAL_PROPERTY_CELL_TYPE)
\
\
V(HEAP_NUMBER_TYPE)
\
+
V(JS_PROXY_TYPE)
\
V(PROXY_TYPE)
\
V(BYTE_ARRAY_TYPE)
\
/* Note: the order of these external array
*/ \
@@ -515,6 +517,7 @@
// objects.
HEAP_NUMBER_TYPE,
PROXY_TYPE,
+ JS_PROXY_TYPE,
BYTE_ARRAY_TYPE,
EXTERNAL_BYTE_ARRAY_TYPE, // FIRST_EXTERNAL_ARRAY_TYPE
EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE,
@@ -720,6 +723,7 @@
V(Proxy) \
V(Boolean) \
V(JSArray) \
+ V(JSProxy) \
V(JSRegExp) \
V(HashTable) \
V(Dictionary) \
@@ -3956,7 +3960,7 @@
// An abstract superclass, a marker class really, for simple structure
classes.
-// It doesn't carry much functionality but allows struct classes to me
+// It doesn't carry much functionality but allows struct classes to be
// identified in the type system.
class Struct: public HeapObject {
public:
@@ -6103,6 +6107,39 @@
};
+// The JSProxy describes EcmaScript Harmony proxies
+class JSProxy: public HeapObject {
+ public:
+ // [handler]: The handler property.
+ DECL_ACCESSORS(handler, Object)
+
+ // Casting.
+ static inline JSProxy* cast(Object* obj);
+
+ // Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void JSProxyPrint() {
+ JSProxyPrint(stdout);
+ }
+ void JSProxyPrint(FILE* out);
+#endif
+#ifdef DEBUG
+ void JSProxyVerify();
+#endif
+
+ // Layout description.
+ static const int kHandlerOffset = HeapObject::kHeaderSize;
+ static const int kSize = kHandlerOffset + kPointerSize;
+
+ typedef FixedBodyDescriptor<kHandlerOffset,
+ kHandlerOffset + kPointerSize,
+ kSize> BodyDescriptor;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(JSProxy);
+};
+
+
// Proxy describes objects pointing from JavaScript to C structures.
// Since they cannot contain references to JS HeapObjects they can be
=======================================
--- /branches/bleeding_edge/src/proxy.js Fri Apr 15 05:31:03 2011
+++ /branches/bleeding_edge/src/proxy.js Fri May 13 03:58:25 2011
@@ -26,3 +26,40 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
global.Proxy = new $Object();
+
+var $Proxy = global.Proxy
+
+var fundamentalTraps = [
+ "getOwnPropertyDescriptor",
+ "getPropertyDescriptor",
+ "getOwnPropertyNames",
+ "getPropertyNames",
+ "defineProperty",
+ "delete",
+ "fix",
+]
+
+var derivedTraps = [
+ "has",
+ "hasOwn",
+ "get",
+ "set",
+ "enumerate",
+ "keys",
+]
+
+var functionTraps = [
+ "callTrap",
+ "constructTrap",
+]
+
+$Proxy.createFunction = function(handler, callTrap, constructTrap) {
+ handler.callTrap = callTrap
+ handler.constructTrap = constructTrap
+ $Proxy.create(handler)
+}
+
+$Proxy.create = function(handler, proto) {
+ if (!IS_SPEC_OBJECT(proto)) proto = $Object.prototype
+ return %CreateJSProxy(handler, proto)
+}
=======================================
--- /branches/bleeding_edge/src/runtime.cc Fri May 13 00:26:44 2011
+++ /branches/bleeding_edge/src/runtime.cc Fri May 13 03:58:25 2011
@@ -586,6 +586,17 @@
}
return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
+ ASSERT(args.length() == 2);
+ Object* handler = args[0];
+ Object* prototype = args[1];
+ Object* used_prototype =
+ (prototype->IsJSObject() || prototype->IsJSProxy()) ? prototype
+ : isolate->heap()->null_value();
+ return isolate->heap()->AllocateJSProxy(handler, used_prototype);
+}
RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
=======================================
--- /branches/bleeding_edge/src/runtime.h Fri May 13 00:26:44 2011
+++ /branches/bleeding_edge/src/runtime.h Fri May 13 03:58:25 2011
@@ -275,6 +275,9 @@
F(CreateArrayLiteral, 3, 1) \
F(CreateArrayLiteralShallow, 3, 1) \
\
+ /* Harmony proxies */ \
+ F(CreateJSProxy, 2, 1) \
+ \
/* Catch context extension objects */ \
F(CreateCatchExtensionObject, 2, 1) \
\
=======================================
--- /branches/bleeding_edge/src/runtime.js Tue May 3 05:15:14 2011
+++ /branches/bleeding_edge/src/runtime.js Fri May 13 03:58:25 2011
@@ -644,6 +644,6 @@
// NOTE: Setting the prototype for Array must take place as early as
// possible due to code generation for array literals. When
// generating code for a array literal a boilerplate array is created
-// that is cloned when running the code. It is essiential that the
+// that is cloned when running the code. It is essential that the
// boilerplate gets the right prototype.
%FunctionSetPrototype($Array, new $Array(0));
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev