js accessor creation on Template
R=svenpanne@chromium.org BUG= Review URL: https://codereview.chromium.org/22903012 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16321 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a29ceb7b27
commit
ad9cc8e716
@ -2982,6 +2982,14 @@ class V8_EXPORT Template : public Data {
|
||||
void Set(Handle<String> name, Handle<Data> value,
|
||||
PropertyAttribute attributes = None);
|
||||
V8_INLINE(void Set(const char* name, Handle<Data> value));
|
||||
|
||||
void SetAccessorProperty(
|
||||
Local<String> name,
|
||||
Local<FunctionTemplate> getter = Local<FunctionTemplate>(),
|
||||
Local<FunctionTemplate> setter = Local<FunctionTemplate>(),
|
||||
PropertyAttribute attribute = None,
|
||||
AccessControl settings = DEFAULT);
|
||||
|
||||
private:
|
||||
Template();
|
||||
|
||||
|
61
src/api.cc
61
src/api.cc
@ -935,21 +935,62 @@ static void InitializeTemplate(i::Handle<i::TemplateInfo> that, int type) {
|
||||
}
|
||||
|
||||
|
||||
void Template::Set(v8::Handle<String> name, v8::Handle<Data> value,
|
||||
static void TemplateSet(i::Isolate* isolate,
|
||||
v8::Template* templ,
|
||||
int length,
|
||||
v8::Handle<v8::Data>* data) {
|
||||
i::Handle<i::Object> list(Utils::OpenHandle(templ)->property_list(), isolate);
|
||||
if (list->IsUndefined()) {
|
||||
list = NeanderArray().value();
|
||||
Utils::OpenHandle(templ)->set_property_list(*list);
|
||||
}
|
||||
NeanderArray array(list);
|
||||
array.add(Utils::OpenHandle(*v8::Integer::New(length)));
|
||||
for (int i = 0; i < length; i++) {
|
||||
i::Handle<i::Object> value = data[i].IsEmpty() ?
|
||||
i::Handle<i::Object>(isolate->factory()->undefined_value()) :
|
||||
Utils::OpenHandle(*data[i]);
|
||||
array.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Template::Set(v8::Handle<String> name,
|
||||
v8::Handle<Data> value,
|
||||
v8::PropertyAttribute attribute) {
|
||||
i::Isolate* isolate = i::Isolate::Current();
|
||||
if (IsDeadCheck(isolate, "v8::Template::Set()")) return;
|
||||
ENTER_V8(isolate);
|
||||
i::HandleScope scope(isolate);
|
||||
i::Handle<i::Object> list(Utils::OpenHandle(this)->property_list(), isolate);
|
||||
if (list->IsUndefined()) {
|
||||
list = NeanderArray().value();
|
||||
Utils::OpenHandle(this)->set_property_list(*list);
|
||||
}
|
||||
NeanderArray array(list);
|
||||
array.add(Utils::OpenHandle(*name));
|
||||
array.add(Utils::OpenHandle(*value));
|
||||
array.add(Utils::OpenHandle(*v8::Integer::New(attribute)));
|
||||
const int kSize = 3;
|
||||
v8::Handle<v8::Data> data[kSize] = {
|
||||
name,
|
||||
value,
|
||||
v8::Integer::New(attribute)};
|
||||
TemplateSet(isolate, this, kSize, data);
|
||||
}
|
||||
|
||||
|
||||
void Template::SetAccessorProperty(
|
||||
v8::Local<v8::String> name,
|
||||
v8::Local<FunctionTemplate> getter,
|
||||
v8::Local<FunctionTemplate> setter,
|
||||
v8::PropertyAttribute attribute,
|
||||
v8::AccessControl access_control) {
|
||||
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
|
||||
if (IsDeadCheck(isolate, "v8::Template::SetAccessor()")) return;
|
||||
ENTER_V8(isolate);
|
||||
ASSERT(!name.IsEmpty());
|
||||
ASSERT(!getter.IsEmpty() || !setter.IsEmpty());
|
||||
i::HandleScope scope(isolate);
|
||||
const int kSize = 5;
|
||||
v8::Handle<v8::Data> data[kSize] = {
|
||||
name,
|
||||
getter,
|
||||
setter,
|
||||
v8::Integer::New(attribute),
|
||||
v8::Integer::New(access_control)};
|
||||
TemplateSet(isolate, this, kSize, data);
|
||||
}
|
||||
|
||||
|
||||
|
@ -104,19 +104,32 @@ function InstantiateFunction(data, name) {
|
||||
|
||||
function ConfigureTemplateInstance(obj, data) {
|
||||
var properties = %GetTemplateField(data, kApiPropertyListOffset);
|
||||
if (properties) {
|
||||
// Disable access checks while instantiating the object.
|
||||
var requires_access_checks = %DisableAccessChecks(obj);
|
||||
try {
|
||||
for (var i = 0; i < properties[0]; i += 3) {
|
||||
if (!properties) return;
|
||||
// Disable access checks while instantiating the object.
|
||||
var requires_access_checks = %DisableAccessChecks(obj);
|
||||
try {
|
||||
for (var i = 1; i < properties[0];) {
|
||||
var length = properties[i];
|
||||
if (length == 3) {
|
||||
var name = properties[i + 1];
|
||||
var prop_data = properties[i + 2];
|
||||
var attributes = properties[i + 3];
|
||||
var value = Instantiate(prop_data, name);
|
||||
%SetProperty(obj, name, value, attributes);
|
||||
} else if (length == 5) {
|
||||
var name = properties[i + 1];
|
||||
var getter = properties[i + 2];
|
||||
var setter = properties[i + 3];
|
||||
var attribute = properties[i + 4];
|
||||
var access_control = properties[i + 5];
|
||||
%SetAccessorProperty(
|
||||
obj, name, getter, setter, attribute, access_control);
|
||||
} else {
|
||||
throw "Bad properties array";
|
||||
}
|
||||
} finally {
|
||||
if (requires_access_checks) %EnableAccessChecks(obj);
|
||||
i += length + 1;
|
||||
}
|
||||
} finally {
|
||||
if (requires_access_checks) %EnableAccessChecks(obj);
|
||||
}
|
||||
}
|
||||
|
@ -2429,6 +2429,7 @@ MaybeObject* Heap::AllocateAccessorPair() {
|
||||
}
|
||||
accessors->set_getter(the_hole_value(), SKIP_WRITE_BARRIER);
|
||||
accessors->set_setter(the_hole_value(), SKIP_WRITE_BARRIER);
|
||||
accessors->set_access_flags(Smi::FromInt(0), SKIP_WRITE_BARRIER);
|
||||
return accessors;
|
||||
}
|
||||
|
||||
|
@ -856,6 +856,7 @@ void AccessorPair::AccessorPairVerify() {
|
||||
CHECK(IsAccessorPair());
|
||||
VerifyPointer(getter());
|
||||
VerifyPointer(setter());
|
||||
VerifySmiField(kAccessFlagsOffset);
|
||||
}
|
||||
|
||||
|
||||
|
@ -4454,6 +4454,7 @@ ACCESSORS(Box, value, Object, kValueOffset)
|
||||
|
||||
ACCESSORS(AccessorPair, getter, Object, kGetterOffset)
|
||||
ACCESSORS(AccessorPair, setter, Object, kSetterOffset)
|
||||
ACCESSORS_TO_SMI(AccessorPair, access_flags, kAccessFlagsOffset)
|
||||
|
||||
ACCESSORS(AccessCheckInfo, named_callback, Object, kNamedCallbackOffset)
|
||||
ACCESSORS(AccessCheckInfo, indexed_callback, Object, kIndexedCallbackOffset)
|
||||
@ -5850,6 +5851,36 @@ bool AccessorInfo::IsCompatibleReceiver(Object* receiver) {
|
||||
}
|
||||
|
||||
|
||||
void AccessorPair::set_access_flags(v8::AccessControl access_control) {
|
||||
int current = access_flags()->value();
|
||||
current = BooleanBit::set(current,
|
||||
kProhibitsOverwritingBit,
|
||||
access_control & PROHIBITS_OVERWRITING);
|
||||
current = BooleanBit::set(current,
|
||||
kAllCanReadBit,
|
||||
access_control & ALL_CAN_READ);
|
||||
current = BooleanBit::set(current,
|
||||
kAllCanWriteBit,
|
||||
access_control & ALL_CAN_WRITE);
|
||||
set_access_flags(Smi::FromInt(current));
|
||||
}
|
||||
|
||||
|
||||
bool AccessorPair::all_can_read() {
|
||||
return BooleanBit::get(access_flags(), kAllCanReadBit);
|
||||
}
|
||||
|
||||
|
||||
bool AccessorPair::all_can_write() {
|
||||
return BooleanBit::get(access_flags(), kAllCanWriteBit);
|
||||
}
|
||||
|
||||
|
||||
bool AccessorPair::prohibits_overwriting() {
|
||||
return BooleanBit::get(access_flags(), kProhibitsOverwritingBit);
|
||||
}
|
||||
|
||||
|
||||
template<typename Shape, typename Key>
|
||||
void Dictionary<Shape, Key>::SetEntry(int entry,
|
||||
Object* key,
|
||||
|
@ -985,6 +985,8 @@ void AccessorPair::AccessorPairPrint(FILE* out) {
|
||||
getter()->ShortPrint(out);
|
||||
PrintF(out, "\n - setter: ");
|
||||
setter()->ShortPrint(out);
|
||||
PrintF(out, "\n - flag: ");
|
||||
access_flags()->ShortPrint(out);
|
||||
}
|
||||
|
||||
|
||||
|
@ -513,6 +513,12 @@ MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
|
||||
return result->holder()->GetPropertyWithCallback(
|
||||
receiver, result->GetCallbackObject(), name);
|
||||
}
|
||||
} else if (obj->IsAccessorPair()) {
|
||||
AccessorPair* pair = AccessorPair::cast(obj);
|
||||
if (pair->all_can_read()) {
|
||||
return result->holder()->GetPropertyWithCallback(
|
||||
receiver, result->GetCallbackObject(), name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -573,6 +579,11 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
|
||||
if (info->all_can_read()) {
|
||||
return result->GetAttributes();
|
||||
}
|
||||
} else if (obj->IsAccessorPair()) {
|
||||
AccessorPair* pair = AccessorPair::cast(obj);
|
||||
if (pair->all_can_read()) {
|
||||
return result->GetAttributes();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -3395,6 +3406,15 @@ MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
|
||||
result->holder(),
|
||||
strict_mode);
|
||||
}
|
||||
} else if (obj->IsAccessorPair()) {
|
||||
AccessorPair* pair = AccessorPair::cast(obj);
|
||||
if (pair->all_can_read()) {
|
||||
return SetPropertyWithCallback(result->GetCallbackObject(),
|
||||
name,
|
||||
value,
|
||||
result->holder(),
|
||||
strict_mode);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -5892,7 +5912,8 @@ void JSObject::DefineElementAccessor(Handle<JSObject> object,
|
||||
uint32_t index,
|
||||
Handle<Object> getter,
|
||||
Handle<Object> setter,
|
||||
PropertyAttributes attributes) {
|
||||
PropertyAttributes attributes,
|
||||
v8::AccessControl access_control) {
|
||||
switch (object->GetElementsKind()) {
|
||||
case FAST_SMI_ELEMENTS:
|
||||
case FAST_ELEMENTS:
|
||||
@ -5950,6 +5971,7 @@ void JSObject::DefineElementAccessor(Handle<JSObject> object,
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair();
|
||||
accessors->SetComponents(*getter, *setter);
|
||||
accessors->set_access_flags(access_control);
|
||||
|
||||
CALL_HEAP_FUNCTION_VOID(
|
||||
isolate, object->SetElementCallback(index, *accessors, attributes));
|
||||
@ -5981,11 +6003,13 @@ void JSObject::DefinePropertyAccessor(Handle<JSObject> object,
|
||||
Handle<Name> name,
|
||||
Handle<Object> getter,
|
||||
Handle<Object> setter,
|
||||
PropertyAttributes attributes) {
|
||||
PropertyAttributes attributes,
|
||||
v8::AccessControl access_control) {
|
||||
// We could assert that the property is configurable here, but we would need
|
||||
// to do a lookup, which seems to be a bit of overkill.
|
||||
bool only_attribute_changes = getter->IsNull() && setter->IsNull();
|
||||
if (object->HasFastProperties() && !only_attribute_changes &&
|
||||
access_control == v8::DEFAULT &&
|
||||
(object->map()->NumberOfOwnDescriptors() <
|
||||
DescriptorArray::kMaxNumberOfDescriptors)) {
|
||||
bool getterOk = getter->IsNull() ||
|
||||
@ -5997,6 +6021,7 @@ void JSObject::DefinePropertyAccessor(Handle<JSObject> object,
|
||||
|
||||
Handle<AccessorPair> accessors = CreateAccessorPairFor(object, name);
|
||||
accessors->SetComponents(*getter, *setter);
|
||||
accessors->set_access_flags(access_control);
|
||||
|
||||
CALL_HEAP_FUNCTION_VOID(
|
||||
object->GetIsolate(),
|
||||
@ -6018,12 +6043,13 @@ bool JSObject::CanSetCallback(Name* name) {
|
||||
LookupCallbackProperty(name, &callback_result);
|
||||
if (callback_result.IsFound()) {
|
||||
Object* obj = callback_result.GetCallbackObject();
|
||||
if (obj->IsAccessorInfo() &&
|
||||
AccessorInfo::cast(obj)->prohibits_overwriting()) {
|
||||
return false;
|
||||
if (obj->IsAccessorInfo()) {
|
||||
return !AccessorInfo::cast(obj)->prohibits_overwriting();
|
||||
}
|
||||
if (obj->IsAccessorPair()) {
|
||||
return !AccessorPair::cast(obj)->prohibits_overwriting();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -6101,7 +6127,8 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
|
||||
Handle<Name> name,
|
||||
Handle<Object> getter,
|
||||
Handle<Object> setter,
|
||||
PropertyAttributes attributes) {
|
||||
PropertyAttributes attributes,
|
||||
v8::AccessControl access_control) {
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
// Check access rights if needed.
|
||||
if (object->IsAccessCheckNeeded() &&
|
||||
@ -6114,8 +6141,12 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
|
||||
Handle<Object> proto(object->GetPrototype(), isolate);
|
||||
if (proto->IsNull()) return;
|
||||
ASSERT(proto->IsJSGlobalObject());
|
||||
DefineAccessor(
|
||||
Handle<JSObject>::cast(proto), name, getter, setter, attributes);
|
||||
DefineAccessor(Handle<JSObject>::cast(proto),
|
||||
name,
|
||||
getter,
|
||||
setter,
|
||||
attributes,
|
||||
access_control);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -6151,9 +6182,11 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
|
||||
}
|
||||
|
||||
if (is_element) {
|
||||
DefineElementAccessor(object, index, getter, setter, attributes);
|
||||
DefineElementAccessor(
|
||||
object, index, getter, setter, attributes, access_control);
|
||||
} else {
|
||||
DefinePropertyAccessor(object, name, getter, setter, attributes);
|
||||
DefinePropertyAccessor(
|
||||
object, name, getter, setter, attributes, access_control);
|
||||
}
|
||||
|
||||
if (is_observed) {
|
||||
|
@ -2252,7 +2252,8 @@ class JSObject: public JSReceiver {
|
||||
Handle<Name> name,
|
||||
Handle<Object> getter,
|
||||
Handle<Object> setter,
|
||||
PropertyAttributes attributes);
|
||||
PropertyAttributes attributes,
|
||||
v8::AccessControl access_control = v8::DEFAULT);
|
||||
|
||||
MaybeObject* LookupAccessor(Name* name, AccessorComponent component);
|
||||
|
||||
@ -2836,14 +2837,16 @@ class JSObject: public JSReceiver {
|
||||
uint32_t index,
|
||||
Handle<Object> getter,
|
||||
Handle<Object> setter,
|
||||
PropertyAttributes attributes);
|
||||
PropertyAttributes attributes,
|
||||
v8::AccessControl access_control);
|
||||
static Handle<AccessorPair> CreateAccessorPairFor(Handle<JSObject> object,
|
||||
Handle<Name> name);
|
||||
static void DefinePropertyAccessor(Handle<JSObject> object,
|
||||
Handle<Name> name,
|
||||
Handle<Object> getter,
|
||||
Handle<Object> setter,
|
||||
PropertyAttributes attributes);
|
||||
PropertyAttributes attributes,
|
||||
v8::AccessControl access_control);
|
||||
|
||||
// Try to define a single accessor paying attention to map transitions.
|
||||
// Returns false if this was not possible and we have to use the slow case.
|
||||
@ -9689,10 +9692,18 @@ class ExecutableAccessorInfo: public AccessorInfo {
|
||||
// * undefined: considered an accessor by the spec, too, strangely enough
|
||||
// * the hole: an accessor which has not been set
|
||||
// * a pointer to a map: a transition used to ensure map sharing
|
||||
// access_flags provides the ability to override access checks on access check
|
||||
// failure.
|
||||
class AccessorPair: public Struct {
|
||||
public:
|
||||
DECL_ACCESSORS(getter, Object)
|
||||
DECL_ACCESSORS(setter, Object)
|
||||
DECL_ACCESSORS(access_flags, Smi)
|
||||
|
||||
inline void set_access_flags(v8::AccessControl access_control);
|
||||
inline bool all_can_read();
|
||||
inline bool all_can_write();
|
||||
inline bool prohibits_overwriting();
|
||||
|
||||
static inline AccessorPair* cast(Object* obj);
|
||||
|
||||
@ -9729,9 +9740,14 @@ class AccessorPair: public Struct {
|
||||
|
||||
static const int kGetterOffset = HeapObject::kHeaderSize;
|
||||
static const int kSetterOffset = kGetterOffset + kPointerSize;
|
||||
static const int kSize = kSetterOffset + kPointerSize;
|
||||
static const int kAccessFlagsOffset = kSetterOffset + kPointerSize;
|
||||
static const int kSize = kAccessFlagsOffset + kPointerSize;
|
||||
|
||||
private:
|
||||
static const int kAllCanReadBit = 0;
|
||||
static const int kAllCanWriteBit = 1;
|
||||
static const int kProhibitsOverwritingBit = 2;
|
||||
|
||||
// Strangely enough, in addition to functions and harmony proxies, the spec
|
||||
// requires us to consider undefined as a kind of accessor, too:
|
||||
// var obj = {};
|
||||
|
@ -1662,6 +1662,14 @@ static bool CheckAccessException(Object* callback,
|
||||
(access_type == v8::ACCESS_GET && info->all_can_read()) ||
|
||||
(access_type == v8::ACCESS_SET && info->all_can_write());
|
||||
}
|
||||
if (callback->IsAccessorPair()) {
|
||||
AccessorPair* info = AccessorPair::cast(callback);
|
||||
return
|
||||
(access_type == v8::ACCESS_HAS &&
|
||||
(info->all_can_read() || info->all_can_write())) ||
|
||||
(access_type == v8::ACCESS_GET && info->all_can_read()) ||
|
||||
(access_type == v8::ACCESS_SET && info->all_can_write());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1943,6 +1951,35 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
|
||||
}
|
||||
|
||||
|
||||
// Transform getter or setter into something DefineAccessor can handle.
|
||||
static Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
|
||||
Handle<Object> component) {
|
||||
if (component->IsUndefined()) return isolate->factory()->null_value();
|
||||
Handle<FunctionTemplateInfo> info =
|
||||
Handle<FunctionTemplateInfo>::cast(component);
|
||||
return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAccessorProperty) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 6);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
|
||||
CONVERT_SMI_ARG_CHECKED(attribute, 4);
|
||||
CONVERT_SMI_ARG_CHECKED(access_control, 5);
|
||||
JSObject::DefineAccessor(object,
|
||||
name,
|
||||
InstantiateAccessorComponent(isolate, getter),
|
||||
InstantiateAccessorComponent(isolate, setter),
|
||||
static_cast<PropertyAttributes>(attribute),
|
||||
static_cast<v8::AccessControl>(access_control));
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
static Failure* ThrowRedeclarationError(Isolate* isolate,
|
||||
const char* type,
|
||||
Handle<String> name) {
|
||||
|
@ -258,6 +258,7 @@ namespace internal {
|
||||
F(GetTemplateField, 2, 1) \
|
||||
F(DisableAccessChecks, 1, 1) \
|
||||
F(EnableAccessChecks, 1, 1) \
|
||||
F(SetAccessorProperty, 6, 1) \
|
||||
\
|
||||
/* Dates */ \
|
||||
F(DateCurrentTime, 0, 1) \
|
||||
|
@ -51,17 +51,33 @@ static void handle_property(Local<String> name,
|
||||
}
|
||||
|
||||
|
||||
static void handle_property(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
ApiTestFuzzer::Fuzz();
|
||||
CHECK_EQ(0, info.Length());
|
||||
info.GetReturnValue().Set(v8_num(907));
|
||||
}
|
||||
|
||||
|
||||
THREADED_TEST(PropertyHandler) {
|
||||
LocalContext env;
|
||||
v8::HandleScope scope(env->GetIsolate());
|
||||
Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
|
||||
fun_templ->InstanceTemplate()->SetAccessor(v8_str("foo"), handle_property);
|
||||
Local<v8::FunctionTemplate> getter_templ =
|
||||
v8::FunctionTemplate::New(handle_property);
|
||||
getter_templ->SetLength(0);
|
||||
fun_templ->
|
||||
InstanceTemplate()->SetAccessorProperty(v8_str("bar"), getter_templ);
|
||||
Local<Function> fun = fun_templ->GetFunction();
|
||||
env->Global()->Set(v8_str("Fun"), fun);
|
||||
Local<Script> getter = v8_compile("var obj = new Fun(); obj.foo;");
|
||||
CHECK_EQ(900, getter->Run()->Int32Value());
|
||||
Local<Script> setter = v8_compile("obj.foo = 901;");
|
||||
CHECK_EQ(901, setter->Run()->Int32Value());
|
||||
getter = v8_compile("obj.bar;");
|
||||
CHECK_EQ(907, getter->Run()->Int32Value());
|
||||
setter = v8_compile("obj.bar = 908;");
|
||||
CHECK_EQ(908, setter->Run()->Int32Value());
|
||||
}
|
||||
|
||||
|
||||
@ -109,30 +125,52 @@ THREADED_TEST(GlobalVariableAccess) {
|
||||
}
|
||||
|
||||
|
||||
static int x_register = 0;
|
||||
static int x_register[2] = {0, 0};
|
||||
static v8::Handle<v8::Object> x_receiver;
|
||||
static v8::Handle<v8::Object> x_holder;
|
||||
|
||||
|
||||
static void XGetter(Local<String> name,
|
||||
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
template<class Info>
|
||||
static void XGetter(const Info& info, int offset) {
|
||||
ApiTestFuzzer::Fuzz();
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
CHECK_EQ(isolate, info.GetIsolate());
|
||||
CHECK_EQ(x_receiver, info.This());
|
||||
info.GetReturnValue().Set(v8_num(x_register[offset]));
|
||||
}
|
||||
|
||||
|
||||
static void XGetter(Local<String> name,
|
||||
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
CHECK_EQ(x_holder, info.Holder());
|
||||
info.GetReturnValue().Set(v8_num(x_register));
|
||||
XGetter(info, 0);
|
||||
}
|
||||
|
||||
|
||||
static void XGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
XGetter(info, 1);
|
||||
}
|
||||
|
||||
|
||||
template<class Info>
|
||||
static void XSetter(Local<Value> value, const Info& info, int offset) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
CHECK_EQ(isolate, info.GetIsolate());
|
||||
CHECK_EQ(x_holder, info.This());
|
||||
x_register[offset] = value->Int32Value();
|
||||
}
|
||||
|
||||
|
||||
static void XSetter(Local<String> name,
|
||||
Local<Value> value,
|
||||
const v8::PropertyCallbackInfo<void>& info) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
CHECK_EQ(isolate, info.GetIsolate());
|
||||
CHECK_EQ(x_holder, info.This());
|
||||
CHECK_EQ(x_holder, info.Holder());
|
||||
x_register = value->Int32Value();
|
||||
XSetter(value, info, 0);
|
||||
}
|
||||
|
||||
|
||||
static void XSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
CHECK_EQ(1, info.Length());
|
||||
XSetter(info[0], info, 1);
|
||||
}
|
||||
|
||||
|
||||
@ -140,7 +178,10 @@ THREADED_TEST(AccessorIC) {
|
||||
LocalContext context;
|
||||
v8::HandleScope scope(context->GetIsolate());
|
||||
v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
|
||||
obj->SetAccessor(v8_str("x"), XGetter, XSetter);
|
||||
obj->SetAccessor(v8_str("x0"), XGetter, XSetter);
|
||||
obj->SetAccessorProperty(v8_str("x1"),
|
||||
v8::FunctionTemplate::New(XGetter),
|
||||
v8::FunctionTemplate::New(XSetter));
|
||||
x_holder = obj->NewInstance();
|
||||
context->Global()->Set(v8_str("holder"), x_holder);
|
||||
x_receiver = v8::Object::New();
|
||||
@ -149,14 +190,16 @@ THREADED_TEST(AccessorIC) {
|
||||
"obj.__proto__ = holder;"
|
||||
"var result = [];"
|
||||
"for (var i = 0; i < 10; i++) {"
|
||||
" holder.x = i;"
|
||||
" result.push(obj.x);"
|
||||
" holder.x0 = i;"
|
||||
" holder.x1 = i;"
|
||||
" result.push(obj.x0);"
|
||||
" result.push(obj.x1);"
|
||||
"}"
|
||||
"result"));
|
||||
CHECK_EQ(10, array->Length());
|
||||
for (int i = 0; i < 10; i++) {
|
||||
CHECK_EQ(20, array->Length());
|
||||
for (int i = 0; i < 20; i++) {
|
||||
v8::Handle<Value> entry = array->Get(v8::Integer::New(i));
|
||||
CHECK_EQ(v8::Integer::New(i), entry);
|
||||
CHECK_EQ(v8::Integer::New(i/2), entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8257,11 +8257,19 @@ static bool IndexedAccessBlocker(Local<v8::Object> global,
|
||||
}
|
||||
|
||||
|
||||
static int g_echo_value = -1;
|
||||
static int g_echo_value_1 = -1;
|
||||
static int g_echo_value_2 = -1;
|
||||
|
||||
|
||||
static void EchoGetter(
|
||||
Local<String> name,
|
||||
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
info.GetReturnValue().Set(v8_num(g_echo_value));
|
||||
info.GetReturnValue().Set(v8_num(g_echo_value_1));
|
||||
}
|
||||
|
||||
|
||||
static void EchoGetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
info.GetReturnValue().Set(v8_num(g_echo_value_2));
|
||||
}
|
||||
|
||||
|
||||
@ -8269,7 +8277,14 @@ static void EchoSetter(Local<String> name,
|
||||
Local<Value> value,
|
||||
const v8::PropertyCallbackInfo<void>&) {
|
||||
if (value->IsNumber())
|
||||
g_echo_value = value->Int32Value();
|
||||
g_echo_value_1 = value->Int32Value();
|
||||
}
|
||||
|
||||
|
||||
static void EchoSetter(const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
v8::Handle<v8::Value> value = info[0];
|
||||
if (value->IsNumber())
|
||||
g_echo_value_2 = value->Int32Value();
|
||||
}
|
||||
|
||||
|
||||
@ -8287,6 +8302,12 @@ static void UnreachableSetter(Local<String>,
|
||||
}
|
||||
|
||||
|
||||
static void UnreachableFunction(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
CHECK(false); // This function should not be called..
|
||||
}
|
||||
|
||||
|
||||
TEST(AccessControl) {
|
||||
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
@ -8302,12 +8323,27 @@ TEST(AccessControl) {
|
||||
v8::Handle<Value>(),
|
||||
v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
|
||||
|
||||
|
||||
global_template->SetAccessorProperty(
|
||||
v8_str("accessible_js_prop"),
|
||||
v8::FunctionTemplate::New(EchoGetter),
|
||||
v8::FunctionTemplate::New(EchoSetter),
|
||||
v8::None,
|
||||
v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
|
||||
|
||||
// Add an accessor that is not accessible by cross-domain JS code.
|
||||
global_template->SetAccessor(v8_str("blocked_prop"),
|
||||
UnreachableGetter, UnreachableSetter,
|
||||
v8::Handle<Value>(),
|
||||
v8::DEFAULT);
|
||||
|
||||
global_template->SetAccessorProperty(
|
||||
v8_str("blocked_js_prop"),
|
||||
v8::FunctionTemplate::New(UnreachableFunction),
|
||||
v8::FunctionTemplate::New(UnreachableFunction),
|
||||
v8::None,
|
||||
v8::DEFAULT);
|
||||
|
||||
// Create an environment
|
||||
v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
|
||||
context0->Enter();
|
||||
@ -8500,26 +8536,47 @@ TEST(AccessControl) {
|
||||
value = CompileRun("other.accessible_prop = 3");
|
||||
CHECK(value->IsNumber());
|
||||
CHECK_EQ(3, value->Int32Value());
|
||||
CHECK_EQ(3, g_echo_value);
|
||||
CHECK_EQ(3, g_echo_value_1);
|
||||
|
||||
// Access accessible js property
|
||||
value = CompileRun("other.accessible_js_prop = 3");
|
||||
CHECK(value->IsNumber());
|
||||
CHECK_EQ(3, value->Int32Value());
|
||||
CHECK_EQ(3, g_echo_value_2);
|
||||
|
||||
value = CompileRun("other.accessible_prop");
|
||||
CHECK(value->IsNumber());
|
||||
CHECK_EQ(3, value->Int32Value());
|
||||
|
||||
value = CompileRun("other.accessible_js_prop");
|
||||
CHECK(value->IsNumber());
|
||||
CHECK_EQ(3, value->Int32Value());
|
||||
|
||||
value = CompileRun(
|
||||
"Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
|
||||
CHECK(value->IsNumber());
|
||||
CHECK_EQ(3, value->Int32Value());
|
||||
|
||||
value = CompileRun(
|
||||
"Object.getOwnPropertyDescriptor(other, 'accessible_js_prop').get()");
|
||||
CHECK(value->IsNumber());
|
||||
CHECK_EQ(3, value->Int32Value());
|
||||
|
||||
value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
|
||||
CHECK(value->IsTrue());
|
||||
|
||||
value = CompileRun("propertyIsEnumerable.call(other, 'accessible_js_prop')");
|
||||
CHECK(value->IsTrue());
|
||||
|
||||
// Enumeration doesn't enumerate accessors from inaccessible objects in
|
||||
// the prototype chain even if the accessors are in themselves accessible.
|
||||
value =
|
||||
CompileRun("(function(){var obj = {'__proto__':other};"
|
||||
"for (var p in obj)"
|
||||
" if (p == 'accessible_prop' || p == 'blocked_prop') {"
|
||||
" if (p == 'accessible_prop' ||"
|
||||
" p == 'accessible_js_prop' ||"
|
||||
" p == 'blocked_js_prop' ||"
|
||||
" p == 'blocked_js_prop') {"
|
||||
" return false;"
|
||||
" }"
|
||||
"return true;})()");
|
||||
@ -8591,7 +8648,7 @@ TEST(AccessControlES5) {
|
||||
// Make sure that we can set the accessible accessors value using normal
|
||||
// assignment.
|
||||
CompileRun("other.accessible_prop = 42");
|
||||
CHECK_EQ(42, g_echo_value);
|
||||
CHECK_EQ(42, g_echo_value_1);
|
||||
|
||||
v8::Handle<Value> value;
|
||||
// We follow Safari in ignoring assignments to host object accessors.
|
||||
|
@ -165,6 +165,7 @@ var knownProblems = {
|
||||
"DeclareGlobals": true,
|
||||
"ArrayConstructor": true,
|
||||
"InternalArrayConstructor": true,
|
||||
"SetAccessorProperty": true,
|
||||
|
||||
"PromoteScheduledException": true,
|
||||
"DeleteHandleScopeExtensions": true,
|
||||
|
@ -227,14 +227,14 @@ KNOWN_OBJECTS = {
|
||||
("OLD_POINTER_SPACE", 0x0a9d9): "NonMonomorphicCache",
|
||||
("OLD_POINTER_SPACE", 0x0afed): "PolymorphicCodeCache",
|
||||
("OLD_POINTER_SPACE", 0x0aff5): "NativesSourceCache",
|
||||
("OLD_POINTER_SPACE", 0x0b035): "EmptyScript",
|
||||
("OLD_POINTER_SPACE", 0x0b06d): "IntrinsicFunctionNames",
|
||||
("OLD_POINTER_SPACE", 0x0e089): "ObservationState",
|
||||
("OLD_POINTER_SPACE", 0x0e095): "FrozenSymbol",
|
||||
("OLD_POINTER_SPACE", 0x0e0a1): "ElementsTransitionSymbol",
|
||||
("OLD_POINTER_SPACE", 0x0e0ad): "EmptySlowElementDictionary",
|
||||
("OLD_POINTER_SPACE", 0x0e249): "ObservedSymbol",
|
||||
("OLD_POINTER_SPACE", 0x274e9): "StringTable",
|
||||
("OLD_POINTER_SPACE", 0x0b03d): "EmptyScript",
|
||||
("OLD_POINTER_SPACE", 0x0b075): "IntrinsicFunctionNames",
|
||||
("OLD_POINTER_SPACE", 0x0e091): "ObservationState",
|
||||
("OLD_POINTER_SPACE", 0x0e09d): "FrozenSymbol",
|
||||
("OLD_POINTER_SPACE", 0x0e0a9): "ElementsTransitionSymbol",
|
||||
("OLD_POINTER_SPACE", 0x0e0b5): "EmptySlowElementDictionary",
|
||||
("OLD_POINTER_SPACE", 0x0e251): "ObservedSymbol",
|
||||
("OLD_POINTER_SPACE", 0x29861): "StringTable",
|
||||
("OLD_DATA_SPACE", 0x08099): "EmptyDescriptorArray",
|
||||
("OLD_DATA_SPACE", 0x080a1): "EmptyFixedArray",
|
||||
("OLD_DATA_SPACE", 0x080a9): "NanValue",
|
||||
@ -250,6 +250,6 @@ KNOWN_OBJECTS = {
|
||||
("OLD_DATA_SPACE", 0x082c9): "EmptyExternalPixelArray",
|
||||
("OLD_DATA_SPACE", 0x082d5): "InfinityValue",
|
||||
("OLD_DATA_SPACE", 0x082e1): "MinusZeroValue",
|
||||
("CODE_SPACE", 0x10d01): "JsConstructEntryCode",
|
||||
("CODE_SPACE", 0x183c1): "JsEntryCode",
|
||||
("CODE_SPACE", 0x114e1): "JsConstructEntryCode",
|
||||
("CODE_SPACE", 0x18ca1): "JsEntryCode",
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user