Implement get trap for proxies.
TODO: reflective Object methods not handled yet. BUG= TEST= Review URL: http://codereview.chromium.org/7035007 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7902 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
daa1be1226
commit
05fd779dd3
@ -2006,8 +2006,9 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
|
||||
break;
|
||||
case NORMAL:
|
||||
// Do not occur since the from object has fast properties.
|
||||
case HANDLER:
|
||||
case INTERCEPTOR:
|
||||
// No element in instance descriptors have interceptor type.
|
||||
// No element in instance descriptors have proxy or interceptor type.
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
@ -237,7 +237,8 @@ enum BuiltinExtraArguments {
|
||||
V(STRING_ADD_LEFT, 1) \
|
||||
V(STRING_ADD_RIGHT, 1) \
|
||||
V(APPLY_PREPARE, 1) \
|
||||
V(APPLY_OVERFLOW, 1)
|
||||
V(APPLY_OVERFLOW, 1) \
|
||||
V(DERIVED_GET_TRAP, 2)
|
||||
|
||||
|
||||
class BuiltinFunctionTable;
|
||||
|
@ -145,11 +145,16 @@ static Handle<Object> Invoke(bool construct,
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> Execution::Call(Handle<JSFunction> func,
|
||||
Handle<Object> Execution::Call(Handle<Object> callable,
|
||||
Handle<Object> receiver,
|
||||
int argc,
|
||||
Object*** args,
|
||||
bool* pending_exception) {
|
||||
if (!callable->IsJSFunction()) {
|
||||
callable = TryGetFunctionDelegate(callable, pending_exception);
|
||||
if (*pending_exception) return callable;
|
||||
}
|
||||
Handle<JSFunction> func = Handle<JSFunction>::cast(callable);
|
||||
return Invoke(false, func, receiver, argc, args, pending_exception);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ class Execution : public AllStatic {
|
||||
// *pending_exception tells whether the invoke resulted in
|
||||
// a pending exception.
|
||||
//
|
||||
static Handle<Object> Call(Handle<JSFunction> func,
|
||||
static Handle<Object> Call(Handle<Object> callable,
|
||||
Handle<Object> receiver,
|
||||
int argc,
|
||||
Object*** args,
|
||||
|
@ -361,6 +361,17 @@ Handle<Object> GetProperty(Handle<JSObject> obj,
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> GetProperty(Handle<Object> obj,
|
||||
const char* name,
|
||||
LookupResult* result) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
Handle<String> str = isolate->factory()->LookupAsciiSymbol(name);
|
||||
PropertyAttributes attributes;
|
||||
CALL_HEAP_FUNCTION(
|
||||
isolate, obj->GetProperty(*obj, result, *str, &attributes), Object);
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> GetProperty(Handle<Object> obj,
|
||||
Handle<Object> key) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
|
@ -242,6 +242,10 @@ Handle<Object> SetOwnElement(Handle<JSObject> object,
|
||||
Handle<Object> GetProperty(Handle<JSObject> obj,
|
||||
const char* name);
|
||||
|
||||
Handle<Object> GetProperty(Handle<Object> obj,
|
||||
const char* name,
|
||||
LookupResult* result);
|
||||
|
||||
Handle<Object> GetProperty(Handle<Object> obj,
|
||||
Handle<Object> key);
|
||||
|
||||
|
@ -903,7 +903,8 @@ MaybeObject* LoadIC::Load(State state,
|
||||
}
|
||||
|
||||
PropertyAttributes attr;
|
||||
if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
|
||||
if (lookup.IsProperty() &&
|
||||
(lookup.type() == INTERCEPTOR || lookup.type() == HANDLER)) {
|
||||
// Get the property.
|
||||
Object* result;
|
||||
{ MaybeObject* maybe_result =
|
||||
|
@ -192,6 +192,7 @@ function FormatMessage(message) {
|
||||
redefine_disallowed: ["Cannot redefine property: ", "%0"],
|
||||
define_disallowed: ["Cannot define property, object is not extensible: ", "%0"],
|
||||
non_extensible_proto: ["%0", " is not extensible"],
|
||||
handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
|
||||
// RangeError
|
||||
invalid_array_length: ["Invalid array length"],
|
||||
stack_overflow: ["Maximum call stack size exceeded"],
|
||||
|
@ -174,11 +174,12 @@ PropertyType.Normal = 0;
|
||||
PropertyType.Field = 1;
|
||||
PropertyType.ConstantFunction = 2;
|
||||
PropertyType.Callbacks = 3;
|
||||
PropertyType.Interceptor = 4;
|
||||
PropertyType.MapTransition = 5;
|
||||
PropertyType.ExternalArrayTransition = 6;
|
||||
PropertyType.ConstantTransition = 7;
|
||||
PropertyType.NullDescriptor = 8;
|
||||
PropertyType.Handler = 4;
|
||||
PropertyType.Interceptor = 5;
|
||||
PropertyType.MapTransition = 6;
|
||||
PropertyType.ExternalArrayTransition = 7;
|
||||
PropertyType.ConstantTransition = 8;
|
||||
PropertyType.NullDescriptor = 9;
|
||||
|
||||
|
||||
// Different attributes for a property.
|
||||
|
@ -149,7 +149,7 @@ void Object::Lookup(String* name, LookupResult* result) {
|
||||
} else if (heap_object->IsBoolean()) {
|
||||
holder = global_context->boolean_function()->instance_prototype();
|
||||
} else if (heap_object->IsJSProxy()) {
|
||||
return result->NotFound(); // For now...
|
||||
return result->HandlerResult();
|
||||
}
|
||||
}
|
||||
ASSERT(holder != NULL); // Cannot handle null or undefined.
|
||||
@ -225,6 +225,36 @@ MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw,
|
||||
String* name_raw,
|
||||
Object* handler_raw) {
|
||||
Isolate* isolate = name_raw->GetIsolate();
|
||||
HandleScope scope;
|
||||
Handle<Object> receiver(receiver_raw);
|
||||
Handle<Object> name(name_raw);
|
||||
Handle<Object> handler(handler_raw);
|
||||
|
||||
// Extract trap function.
|
||||
LookupResult lookup;
|
||||
Handle<Object> trap(v8::internal::GetProperty(handler, "get", &lookup));
|
||||
if (!lookup.IsFound()) {
|
||||
// Get the derived `get' property.
|
||||
Object* derived = isolate->global_context()->builtins()->javascript_builtin(
|
||||
Builtins::DERIVED_GET_TRAP);
|
||||
trap = Handle<JSFunction>(JSFunction::cast(derived));
|
||||
}
|
||||
|
||||
// Call trap function.
|
||||
Object** args[] = { receiver.location(), name.location() };
|
||||
bool has_exception;
|
||||
Handle<Object> result =
|
||||
Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
|
||||
if (has_exception) return Failure::Exception();
|
||||
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
||||
MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
|
||||
JSFunction* getter) {
|
||||
HandleScope scope;
|
||||
@ -497,26 +527,29 @@ MaybeObject* Object::GetProperty(Object* receiver,
|
||||
// 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
|
||||
// that even though we may not actually end up loading the named
|
||||
// property from the current object, we still check that we have
|
||||
// access to it.
|
||||
JSObject* checked = JSObject::cast(current);
|
||||
if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
|
||||
return checked->GetPropertyWithFailedAccessCheck(receiver,
|
||||
result,
|
||||
name,
|
||||
attributes);
|
||||
// Proxy handlers do not use the proxy's prototype, so we can skip this.
|
||||
if (!result->IsHandler()) {
|
||||
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
|
||||
// that even though we may not actually end up loading the named
|
||||
// property from the current object, we still check that we have
|
||||
// access to it.
|
||||
JSObject* checked = JSObject::cast(current);
|
||||
if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
|
||||
return checked->GetPropertyWithFailedAccessCheck(receiver,
|
||||
result,
|
||||
name,
|
||||
attributes);
|
||||
}
|
||||
}
|
||||
// Stop traversing the chain once we reach the last object in the
|
||||
// chain; either the holder of the result or null in case of an
|
||||
// absent property.
|
||||
if (current == last) break;
|
||||
}
|
||||
// Stop traversing the chain once we reach the last object in the
|
||||
// chain; either the holder of the result or null in case of an
|
||||
// absent property.
|
||||
if (current == last) break;
|
||||
}
|
||||
|
||||
if (!result->IsProperty()) {
|
||||
@ -542,14 +575,22 @@ MaybeObject* Object::GetProperty(Object* receiver,
|
||||
result->GetCallbackObject(),
|
||||
name,
|
||||
holder);
|
||||
case HANDLER: {
|
||||
JSProxy* proxy = JSProxy::cast(this);
|
||||
return GetPropertyWithHandler(receiver, name, proxy->handler());
|
||||
}
|
||||
case INTERCEPTOR: {
|
||||
JSObject* recvr = JSObject::cast(receiver);
|
||||
return holder->GetPropertyWithInterceptor(recvr, name, attributes);
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return NULL;
|
||||
case MAP_TRANSITION:
|
||||
case EXTERNAL_ARRAY_TRANSITION:
|
||||
case CONSTANT_TRANSITION:
|
||||
case NULL_DESCRIPTOR:
|
||||
break;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -6550,6 +6591,7 @@ const char* Code::PropertyType2String(PropertyType type) {
|
||||
case FIELD: return "FIELD";
|
||||
case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
|
||||
case CALLBACKS: return "CALLBACKS";
|
||||
case HANDLER: return "HANDLER";
|
||||
case INTERCEPTOR: return "INTERCEPTOR";
|
||||
case MAP_TRANSITION: return "MAP_TRANSITION";
|
||||
case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
|
||||
|
@ -808,6 +808,9 @@ class Object : public MaybeObject {
|
||||
Object* structure,
|
||||
String* name,
|
||||
Object* holder);
|
||||
MUST_USE_RESULT MaybeObject* GetPropertyWithHandler(Object* receiver,
|
||||
String* name,
|
||||
Object* handler);
|
||||
MUST_USE_RESULT MaybeObject* GetPropertyWithDefinedGetter(Object* receiver,
|
||||
JSFunction* getter);
|
||||
|
||||
|
@ -74,6 +74,9 @@ void LookupResult::Print(FILE* out) {
|
||||
PrintF(out, " -callback object:\n");
|
||||
GetCallbackObject()->Print(out);
|
||||
break;
|
||||
case HANDLER:
|
||||
PrintF(out, " -type = lookup proxy\n");
|
||||
break;
|
||||
case INTERCEPTOR:
|
||||
PrintF(out, " -type = lookup interceptor\n");
|
||||
break;
|
||||
|
@ -166,15 +166,6 @@ class CallbacksDescriptor: public Descriptor {
|
||||
|
||||
class LookupResult BASE_EMBEDDED {
|
||||
public:
|
||||
// Where did we find the result;
|
||||
enum {
|
||||
NOT_FOUND,
|
||||
DESCRIPTOR_TYPE,
|
||||
DICTIONARY_TYPE,
|
||||
INTERCEPTOR_TYPE,
|
||||
CONSTANT_TYPE
|
||||
} lookup_type_;
|
||||
|
||||
LookupResult()
|
||||
: lookup_type_(NOT_FOUND),
|
||||
cacheable_(true),
|
||||
@ -211,6 +202,12 @@ class LookupResult BASE_EMBEDDED {
|
||||
number_ = entry;
|
||||
}
|
||||
|
||||
void HandlerResult() {
|
||||
lookup_type_ = HANDLER_TYPE;
|
||||
holder_ = NULL;
|
||||
details_ = PropertyDetails(NONE, HANDLER);
|
||||
}
|
||||
|
||||
void InterceptorResult(JSObject* holder) {
|
||||
lookup_type_ = INTERCEPTOR_TYPE;
|
||||
holder_ = holder;
|
||||
@ -245,6 +242,7 @@ class LookupResult BASE_EMBEDDED {
|
||||
bool IsDontEnum() { return details_.IsDontEnum(); }
|
||||
bool IsDeleted() { return details_.IsDeleted(); }
|
||||
bool IsFound() { return lookup_type_ != NOT_FOUND; }
|
||||
bool IsHandler() { return lookup_type_ == HANDLER_TYPE; }
|
||||
|
||||
// Is the result is a property excluding transitions and the null
|
||||
// descriptor?
|
||||
@ -345,6 +343,16 @@ class LookupResult BASE_EMBEDDED {
|
||||
}
|
||||
|
||||
private:
|
||||
// Where did we find the result;
|
||||
enum {
|
||||
NOT_FOUND,
|
||||
DESCRIPTOR_TYPE,
|
||||
DICTIONARY_TYPE,
|
||||
HANDLER_TYPE,
|
||||
INTERCEPTOR_TYPE,
|
||||
CONSTANT_TYPE
|
||||
} lookup_type_;
|
||||
|
||||
JSObject* holder_;
|
||||
int number_;
|
||||
bool cacheable_;
|
||||
|
@ -647,3 +647,20 @@ function DefaultString(x) {
|
||||
// that is cloned when running the code. It is essential that the
|
||||
// boilerplate gets the right prototype.
|
||||
%FunctionSetPrototype($Array, new $Array(0));
|
||||
|
||||
|
||||
/* ------------------------------------------
|
||||
- - - H a r m o n y P r o x i e s - - -
|
||||
---------------------------------------------
|
||||
*/
|
||||
|
||||
function DERIVED_GET_TRAP(receiver, name) {
|
||||
var desc = this.getPropertyDescriptor(name);
|
||||
if (IS_UNDEFINED(desc)) { return desc; }
|
||||
if ('value' in desc) {
|
||||
return desc.value;
|
||||
} else {
|
||||
if (IS_UNDEFINED(desc.get)) { return desc.get; }
|
||||
return desc.get().call(receiver); // The proposal says so...
|
||||
}
|
||||
}
|
||||
|
@ -322,11 +322,12 @@ enum PropertyType {
|
||||
FIELD = 1, // only in fast mode
|
||||
CONSTANT_FUNCTION = 2, // only in fast mode
|
||||
CALLBACKS = 3,
|
||||
INTERCEPTOR = 4, // only in lookup results, not in descriptors.
|
||||
MAP_TRANSITION = 5, // only in fast mode
|
||||
EXTERNAL_ARRAY_TRANSITION = 6,
|
||||
CONSTANT_TRANSITION = 7, // only in fast mode
|
||||
NULL_DESCRIPTOR = 8, // only in fast mode
|
||||
HANDLER = 4, // only in lookup results, not in descriptors
|
||||
INTERCEPTOR = 5, // only in lookup results, not in descriptors
|
||||
MAP_TRANSITION = 6, // only in fast mode
|
||||
EXTERNAL_ARRAY_TRANSITION = 7,
|
||||
CONSTANT_TRANSITION = 8, // only in fast mode
|
||||
NULL_DESCRIPTOR = 9, // only in fast mode
|
||||
// All properties before MAP_TRANSITION are real.
|
||||
FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION,
|
||||
// There are no IC stubs for NULL_DESCRIPTORS. Therefore,
|
||||
|
@ -4264,9 +4264,9 @@ TEST(InterceptorPropertyMirror) {
|
||||
"named_values[%d] instanceof debug.PropertyMirror", i);
|
||||
CHECK(CompileRun(buffer.start())->BooleanValue());
|
||||
|
||||
// 4 is PropertyType.Interceptor
|
||||
// 5 is PropertyType.Interceptor
|
||||
OS::SNPrintF(buffer, "named_values[%d].propertyType()", i);
|
||||
CHECK_EQ(4, CompileRun(buffer.start())->Int32Value());
|
||||
CHECK_EQ(5, CompileRun(buffer.start())->Int32Value());
|
||||
|
||||
OS::SNPrintF(buffer, "named_values[%d].isNative()", i);
|
||||
CHECK(CompileRun(buffer.start())->BooleanValue());
|
||||
|
Loading…
Reference in New Issue
Block a user