Port number dictionary probing in generated code to ARM.
Fix bug in ARM pixel array load code and a typo in the x64 number dictionary load code. Fix bug in string dictionary probing where we did not bail out if the object has an interceptor. BUG=640 Review URL: http://codereview.chromium.org/1332003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4292 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
2d0c823305
commit
2bcc49740c
@ -65,11 +65,11 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
|
|||||||
// Check for the absence of an interceptor.
|
// Check for the absence of an interceptor.
|
||||||
// Load the map into t0.
|
// Load the map into t0.
|
||||||
__ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset));
|
__ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset));
|
||||||
// Test the has_named_interceptor bit in the map.
|
|
||||||
__ ldr(r3, FieldMemOperand(t0, Map::kInstanceAttributesOffset));
|
// Bail out if the receiver has a named interceptor.
|
||||||
__ tst(r3, Operand(1 << (Map::kHasNamedInterceptor + (3 * 8))));
|
__ ldrb(r3, FieldMemOperand(t0, Map::kBitFieldOffset));
|
||||||
// Jump to miss if the interceptor bit is set.
|
__ tst(r3, Operand(1 << Map::kHasNamedInterceptor));
|
||||||
__ b(ne, miss);
|
__ b(nz, miss);
|
||||||
|
|
||||||
// Bail out if we have a JS global proxy object.
|
// Bail out if we have a JS global proxy object.
|
||||||
__ ldrb(r3, FieldMemOperand(t0, Map::kInstanceTypeOffset));
|
__ ldrb(r3, FieldMemOperand(t0, Map::kInstanceTypeOffset));
|
||||||
@ -144,6 +144,95 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
|
||||||
|
Label* miss,
|
||||||
|
Register elements,
|
||||||
|
Register key,
|
||||||
|
Register t0,
|
||||||
|
Register t1,
|
||||||
|
Register t2) {
|
||||||
|
// Register use:
|
||||||
|
//
|
||||||
|
// elements - holds the slow-case elements of the receiver and is unchanged.
|
||||||
|
//
|
||||||
|
// key - holds the smi key on entry and is unchanged if a branch is
|
||||||
|
// performed to the miss label.
|
||||||
|
//
|
||||||
|
// Scratch registers:
|
||||||
|
//
|
||||||
|
// t0 - holds the untagged key on entry and holds the hash once computed.
|
||||||
|
// Holds the result on exit if the load succeeded.
|
||||||
|
//
|
||||||
|
// t1 - used to hold the capacity mask of the dictionary
|
||||||
|
//
|
||||||
|
// t2 - used for the index into the dictionary.
|
||||||
|
Label done;
|
||||||
|
|
||||||
|
// Compute the hash code from the untagged key. This must be kept in sync
|
||||||
|
// with ComputeIntegerHash in utils.h.
|
||||||
|
//
|
||||||
|
// hash = ~hash + (hash << 15);
|
||||||
|
__ mvn(t1, Operand(t0));
|
||||||
|
__ add(t0, t1, Operand(t0, LSL, 15));
|
||||||
|
// hash = hash ^ (hash >> 12);
|
||||||
|
__ eor(t0, t0, Operand(t0, LSR, 12));
|
||||||
|
// hash = hash + (hash << 2);
|
||||||
|
__ add(t0, t0, Operand(t0, LSL, 2));
|
||||||
|
// hash = hash ^ (hash >> 4);
|
||||||
|
__ eor(t0, t0, Operand(t0, LSR, 4));
|
||||||
|
// hash = hash * 2057;
|
||||||
|
__ mov(t1, Operand(2057));
|
||||||
|
__ mul(t0, t0, t1);
|
||||||
|
// hash = hash ^ (hash >> 16);
|
||||||
|
__ eor(t0, t0, Operand(t0, LSR, 16));
|
||||||
|
|
||||||
|
// Compute the capacity mask.
|
||||||
|
__ ldr(t1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
|
||||||
|
__ mov(t1, Operand(t1, ASR, kSmiTagSize)); // convert smi to int
|
||||||
|
__ sub(t1, t1, Operand(1));
|
||||||
|
|
||||||
|
// Generate an unrolled loop that performs a few probes before giving up.
|
||||||
|
static const int kProbes = 4;
|
||||||
|
for (int i = 0; i < kProbes; i++) {
|
||||||
|
// Use t2 for index calculations and keep the hash intact in t0.
|
||||||
|
__ mov(t2, t0);
|
||||||
|
// Compute the masked index: (hash + i + i * i) & mask.
|
||||||
|
if (i > 0) {
|
||||||
|
__ add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i)));
|
||||||
|
}
|
||||||
|
__ and_(t2, t2, Operand(t1));
|
||||||
|
|
||||||
|
// Scale the index by multiplying by the element size.
|
||||||
|
ASSERT(NumberDictionary::kEntrySize == 3);
|
||||||
|
__ add(t2, t2, Operand(t2, LSL, 1)); // t2 = t2 * 3
|
||||||
|
|
||||||
|
// Check if the key is identical to the name.
|
||||||
|
__ add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
|
||||||
|
__ ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset));
|
||||||
|
__ cmp(key, Operand(ip));
|
||||||
|
if (i != kProbes - 1) {
|
||||||
|
__ b(eq, &done);
|
||||||
|
} else {
|
||||||
|
__ b(ne, miss);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__ bind(&done);
|
||||||
|
// Check that the value is a normal property.
|
||||||
|
// t2: elements + (index * kPointerSize)
|
||||||
|
const int kDetailsOffset =
|
||||||
|
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
|
||||||
|
__ ldr(t1, FieldMemOperand(t2, kDetailsOffset));
|
||||||
|
__ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
|
||||||
|
__ b(ne, miss);
|
||||||
|
|
||||||
|
// Get the value at the masked, scaled index and return.
|
||||||
|
const int kValueOffset =
|
||||||
|
NumberDictionary::kElementsStartOffset + kPointerSize;
|
||||||
|
__ ldr(t0, FieldMemOperand(t2, kValueOffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
|
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- r2 : name
|
// -- r2 : name
|
||||||
@ -530,7 +619,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
// -- sp[0] : key
|
// -- sp[0] : key
|
||||||
// -- sp[4] : receiver
|
// -- sp[4] : receiver
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label slow, fast, check_pixel_array;
|
Label slow, fast, check_pixel_array, check_number_dictionary;
|
||||||
|
|
||||||
// Get the key and receiver object from the stack.
|
// Get the key and receiver object from the stack.
|
||||||
__ ldm(ia, sp, r0.bit() | r1.bit());
|
__ ldm(ia, sp, r0.bit() | r1.bit());
|
||||||
@ -554,6 +643,8 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
|
|
||||||
// Check that the key is a smi.
|
// Check that the key is a smi.
|
||||||
__ BranchOnNotSmi(r0, &slow);
|
__ BranchOnNotSmi(r0, &slow);
|
||||||
|
// Save key in r2 in case we want it for the number dictionary case.
|
||||||
|
__ mov(r2, r0);
|
||||||
__ mov(r0, Operand(r0, ASR, kSmiTagSize));
|
__ mov(r0, Operand(r0, ASR, kSmiTagSize));
|
||||||
|
|
||||||
// Get the elements array of the object.
|
// Get the elements array of the object.
|
||||||
@ -562,17 +653,26 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
|
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
|
||||||
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
|
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
|
||||||
__ cmp(r3, ip);
|
__ cmp(r3, ip);
|
||||||
__ b(ne, &slow);
|
__ b(ne, &check_pixel_array);
|
||||||
// Check that the key (index) is within bounds.
|
// Check that the key (index) is within bounds.
|
||||||
__ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
|
__ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
|
||||||
__ cmp(r0, Operand(r3));
|
__ cmp(r0, Operand(r3));
|
||||||
__ b(lo, &fast);
|
__ b(ge, &slow);
|
||||||
|
// Fast case: Do the load.
|
||||||
|
__ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
||||||
|
__ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
|
||||||
|
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
||||||
|
__ cmp(r0, ip);
|
||||||
|
// In case the loaded value is the_hole we have to consult GetProperty
|
||||||
|
// to ensure the prototype chain is searched.
|
||||||
|
__ b(eq, &slow);
|
||||||
|
__ Ret();
|
||||||
|
|
||||||
// Check whether the elements is a pixel array.
|
// Check whether the elements is a pixel array.
|
||||||
__ bind(&check_pixel_array);
|
__ bind(&check_pixel_array);
|
||||||
__ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
|
__ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
|
||||||
__ cmp(r3, ip);
|
__ cmp(r3, ip);
|
||||||
__ b(ne, &slow);
|
__ b(ne, &check_number_dictionary);
|
||||||
__ ldr(ip, FieldMemOperand(r1, PixelArray::kLengthOffset));
|
__ ldr(ip, FieldMemOperand(r1, PixelArray::kLengthOffset));
|
||||||
__ cmp(r0, ip);
|
__ cmp(r0, ip);
|
||||||
__ b(hs, &slow);
|
__ b(hs, &slow);
|
||||||
@ -581,22 +681,21 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
__ mov(r0, Operand(r0, LSL, kSmiTagSize)); // Tag result as smi.
|
__ mov(r0, Operand(r0, LSL, kSmiTagSize)); // Tag result as smi.
|
||||||
__ Ret();
|
__ Ret();
|
||||||
|
|
||||||
|
__ bind(&check_number_dictionary);
|
||||||
|
// Check whether the elements is a number dictionary.
|
||||||
|
// r0: untagged index
|
||||||
|
// r1: elements
|
||||||
|
// r2: key
|
||||||
|
__ LoadRoot(ip, Heap::kHashTableMapRootIndex);
|
||||||
|
__ cmp(r3, ip);
|
||||||
|
__ b(ne, &slow);
|
||||||
|
GenerateNumberDictionaryLoad(masm, &slow, r1, r2, r0, r3, r4);
|
||||||
|
__ Ret();
|
||||||
|
|
||||||
// Slow case: Push extra copies of the arguments (2).
|
// Slow case: Push extra copies of the arguments (2).
|
||||||
__ bind(&slow);
|
__ bind(&slow);
|
||||||
__ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r0, r1);
|
__ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r0, r1);
|
||||||
GenerateRuntimeGetProperty(masm);
|
GenerateRuntimeGetProperty(masm);
|
||||||
|
|
||||||
// Fast case: Do the load.
|
|
||||||
__ bind(&fast);
|
|
||||||
__ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
|
||||||
__ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
|
|
||||||
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
|
||||||
__ cmp(r0, ip);
|
|
||||||
// In case the loaded value is the_hole we have to consult GetProperty
|
|
||||||
// to ensure the prototype chain is searched.
|
|
||||||
__ b(eq, &slow);
|
|
||||||
|
|
||||||
__ Ret();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,11 +73,10 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
|
|||||||
// Check for the absence of an interceptor.
|
// Check for the absence of an interceptor.
|
||||||
// Load the map into r0.
|
// Load the map into r0.
|
||||||
__ mov(r0, FieldOperand(receiver, JSObject::kMapOffset));
|
__ mov(r0, FieldOperand(receiver, JSObject::kMapOffset));
|
||||||
// Test the has_named_interceptor bit in the map.
|
|
||||||
__ test(FieldOperand(r0, Map::kInstanceAttributesOffset),
|
|
||||||
Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
|
|
||||||
|
|
||||||
// Jump to miss if the interceptor bit is set.
|
// Bail out if the receiver has a named interceptor.
|
||||||
|
__ test(FieldOperand(r0, Map::kBitFieldOffset),
|
||||||
|
Immediate(1 << Map::kHasNamedInterceptor));
|
||||||
__ j(not_zero, miss_label, not_taken);
|
__ j(not_zero, miss_label, not_taken);
|
||||||
|
|
||||||
// Bail out if we have a JS global proxy object.
|
// Bail out if we have a JS global proxy object.
|
||||||
@ -202,17 +201,10 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
|
|||||||
__ xor_(r0, Operand(r1));
|
__ xor_(r0, Operand(r1));
|
||||||
|
|
||||||
// Compute capacity mask.
|
// Compute capacity mask.
|
||||||
const int kCapacityOffset =
|
__ mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
|
||||||
NumberDictionary::kHeaderSize +
|
|
||||||
NumberDictionary::kCapacityIndex * kPointerSize;
|
|
||||||
__ mov(r1, FieldOperand(elements, kCapacityOffset));
|
|
||||||
__ shr(r1, kSmiTagSize); // convert smi to int
|
__ shr(r1, kSmiTagSize); // convert smi to int
|
||||||
__ dec(r1);
|
__ dec(r1);
|
||||||
|
|
||||||
const int kElementsStartOffset =
|
|
||||||
NumberDictionary::kHeaderSize +
|
|
||||||
NumberDictionary::kElementsStartIndex * kPointerSize;
|
|
||||||
|
|
||||||
// Generate an unrolled loop that performs a few probes before giving up.
|
// Generate an unrolled loop that performs a few probes before giving up.
|
||||||
const int kProbes = 4;
|
const int kProbes = 4;
|
||||||
for (int i = 0; i < kProbes; i++) {
|
for (int i = 0; i < kProbes; i++) {
|
||||||
@ -232,7 +224,7 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
|
|||||||
__ cmp(key, FieldOperand(elements,
|
__ cmp(key, FieldOperand(elements,
|
||||||
r2,
|
r2,
|
||||||
times_pointer_size,
|
times_pointer_size,
|
||||||
kElementsStartOffset));
|
NumberDictionary::kElementsStartOffset));
|
||||||
if (i != (kProbes - 1)) {
|
if (i != (kProbes - 1)) {
|
||||||
__ j(equal, &done, taken);
|
__ j(equal, &done, taken);
|
||||||
} else {
|
} else {
|
||||||
@ -242,14 +234,16 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
|
|||||||
|
|
||||||
__ bind(&done);
|
__ bind(&done);
|
||||||
// Check that the value is a normal propety.
|
// Check that the value is a normal propety.
|
||||||
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
|
const int kDetailsOffset =
|
||||||
|
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
|
||||||
ASSERT_EQ(NORMAL, 0);
|
ASSERT_EQ(NORMAL, 0);
|
||||||
__ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
|
__ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
|
||||||
Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
|
Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
|
||||||
__ j(not_zero, miss);
|
__ j(not_zero, miss);
|
||||||
|
|
||||||
// Get the value at the masked, scaled index.
|
// Get the value at the masked, scaled index.
|
||||||
const int kValueOffset = kElementsStartOffset + kPointerSize;
|
const int kValueOffset =
|
||||||
|
NumberDictionary::kElementsStartOffset + kPointerSize;
|
||||||
__ mov(key, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
|
__ mov(key, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,11 +72,10 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
|
|||||||
// Check for the absence of an interceptor.
|
// Check for the absence of an interceptor.
|
||||||
// Load the map into r0.
|
// Load the map into r0.
|
||||||
__ movq(r0, FieldOperand(r1, JSObject::kMapOffset));
|
__ movq(r0, FieldOperand(r1, JSObject::kMapOffset));
|
||||||
// Test the has_named_interceptor bit in the map.
|
|
||||||
__ testl(FieldOperand(r0, Map::kInstanceAttributesOffset),
|
|
||||||
Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
|
|
||||||
|
|
||||||
// Jump to miss if the interceptor bit is set.
|
// Bail out if the receiver has a named interceptor.
|
||||||
|
__ testl(FieldOperand(r0, Map::kBitFieldOffset),
|
||||||
|
Immediate(1 << Map::kHasNamedInterceptor));
|
||||||
__ j(not_zero, miss_label);
|
__ j(not_zero, miss_label);
|
||||||
|
|
||||||
// Bail out if we have a JS global proxy object.
|
// Bail out if we have a JS global proxy object.
|
||||||
@ -201,17 +200,10 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
|
|||||||
__ xorl(r0, r1);
|
__ xorl(r0, r1);
|
||||||
|
|
||||||
// Compute capacity mask.
|
// Compute capacity mask.
|
||||||
const int kCapacityOffset =
|
__ movq(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
|
||||||
StringDictionary::kHeaderSize +
|
|
||||||
StringDictionary::kCapacityIndex * kPointerSize;
|
|
||||||
__ movq(r1, FieldOperand(elements, kCapacityOffset));
|
|
||||||
__ SmiToInteger32(r1, r1);
|
__ SmiToInteger32(r1, r1);
|
||||||
__ decl(r1);
|
__ decl(r1);
|
||||||
|
|
||||||
const int kElementsStartOffset =
|
|
||||||
NumberDictionary::kHeaderSize +
|
|
||||||
NumberDictionary::kElementsStartIndex * kPointerSize;
|
|
||||||
|
|
||||||
// Generate an unrolled loop that performs a few probes before giving up.
|
// Generate an unrolled loop that performs a few probes before giving up.
|
||||||
const int kProbes = 4;
|
const int kProbes = 4;
|
||||||
for (int i = 0; i < kProbes; i++) {
|
for (int i = 0; i < kProbes; i++) {
|
||||||
@ -231,7 +223,7 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
|
|||||||
__ cmpq(key, FieldOperand(elements,
|
__ cmpq(key, FieldOperand(elements,
|
||||||
r2,
|
r2,
|
||||||
times_pointer_size,
|
times_pointer_size,
|
||||||
kElementsStartOffset));
|
NumberDictionary::kElementsStartOffset));
|
||||||
if (i != (kProbes - 1)) {
|
if (i != (kProbes - 1)) {
|
||||||
__ j(equal, &done);
|
__ j(equal, &done);
|
||||||
} else {
|
} else {
|
||||||
@ -241,14 +233,16 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
|
|||||||
|
|
||||||
__ bind(&done);
|
__ bind(&done);
|
||||||
// Check that the value is a normal propety.
|
// Check that the value is a normal propety.
|
||||||
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
|
const int kDetailsOffset =
|
||||||
|
NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
|
||||||
ASSERT_EQ(NORMAL, 0);
|
ASSERT_EQ(NORMAL, 0);
|
||||||
__ Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
|
__ Test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
|
||||||
Smi::FromInt(PropertyDetails::TypeField::mask()));
|
Smi::FromInt(PropertyDetails::TypeField::mask()));
|
||||||
__ j(not_zero, miss);
|
__ j(not_zero, miss);
|
||||||
|
|
||||||
// Get the value at the masked, scaled index.
|
// Get the value at the masked, scaled index.
|
||||||
const int kValueOffset = kElementsStartOffset + kPointerSize;
|
const int kValueOffset =
|
||||||
|
NumberDictionary::kElementsStartOffset + kPointerSize;
|
||||||
__ movq(r0, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
|
__ movq(r0, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2644,6 +2644,36 @@ THREADED_TEST(NamedInterceptorPropertyRead) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
THREADED_TEST(NamedInterceptorDictionaryIC) {
|
||||||
|
v8::HandleScope scope;
|
||||||
|
Local<ObjectTemplate> templ = ObjectTemplate::New();
|
||||||
|
templ->SetNamedPropertyHandler(XPropertyGetter);
|
||||||
|
LocalContext context;
|
||||||
|
// Create an object with a named interceptor.
|
||||||
|
context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
|
||||||
|
Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
Local<Value> result = script->Run();
|
||||||
|
CHECK_EQ(result, v8_str("x"));
|
||||||
|
}
|
||||||
|
// Create a slow case object and a function accessing a property in
|
||||||
|
// that slow case object (with dictionary probing in generated
|
||||||
|
// code). Then force object with a named interceptor into slow-case,
|
||||||
|
// pass it to the function, and check that the interceptor is called
|
||||||
|
// instead of accessing the local property.
|
||||||
|
Local<Value> result =
|
||||||
|
CompileRun("function get_x(o) { return o.x; };"
|
||||||
|
"var obj = { x : 42, y : 0 };"
|
||||||
|
"delete obj.y;"
|
||||||
|
"for (var i = 0; i < 10; i++) get_x(obj);"
|
||||||
|
"interceptor_obj.x = 42;"
|
||||||
|
"interceptor_obj.y = 10;"
|
||||||
|
"delete interceptor_obj.y;"
|
||||||
|
"get_x(interceptor_obj)");
|
||||||
|
CHECK_EQ(result, v8_str("x"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
|
static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property,
|
||||||
const AccessorInfo& info) {
|
const AccessorInfo& info) {
|
||||||
// Set x on the prototype object and do not handle the get request.
|
// Set x on the prototype object and do not handle the get request.
|
||||||
|
Loading…
Reference in New Issue
Block a user