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;
}
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;
}
-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);
}
// *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,
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();
CALL_HEAP_FUNCTION(isolate,
const char* name);
Handle<Object> GetProperty(Handle<Object> obj,
+ const char* name,
+ LookupResult* result);
+
+Handle<Object> GetProperty(Handle<Object> obj,
Handle<Object> key);
Handle<Object> GetProperty(Handle<JSObject> obj,
}
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 =
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"],
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.
} 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.
}
+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;
// 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);
- }
- }
- // 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;
+ // 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;
+ }
}
if (!result->IsProperty()) {
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;
}
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";
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);
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;
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),
number_ = entry;
}
+ void HandlerResult() {
+ lookup_type_ = HANDLER_TYPE;
+ holder_ = NULL;
+ details_ = PropertyDetails(NONE, HANDLER);
+ }
+
void InterceptorResult(JSObject* holder) {
lookup_type_ = INTERCEPTOR_TYPE;
holder_ = holder;
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?
}
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_;
// 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...
+ }
+}
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,
"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());