Add missing negative dictionary lookup to NonexistentHandlerFrontend

BUG=v8:2980
R=verwaest@chromium.org

Review URL: https://codereview.chromium.org/57433003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17459 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4fbc96ff
......@@ -121,18 +121,14 @@ static void ProbeTable(Isolate* isolate,
}
// Helper function used to check that the dictionary doesn't contain
// the property. This function may return false negatives, so miss_label
// must always call a backup property check that is complete.
// This function is safe to call if the receiver has fast properties.
// Name must be unique and receiver must be a heap object.
static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
void StubCompiler::GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Label* miss_label,
Register receiver,
Handle<Name> name,
Register scratch0,
Register scratch1) {
ASSERT(name->IsUniqueName());
ASSERT(!receiver.is(scratch0));
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
__ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
......@@ -418,7 +414,7 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
static void GenerateCheckPropertyCell(MacroAssembler* masm,
void StubCompiler::GenerateCheckPropertyCell(MacroAssembler* masm,
Handle<GlobalObject> global,
Handle<Name> name,
Register scratch,
......@@ -1156,9 +1152,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
};
// Calls GenerateCheckPropertyCell for each global object in the prototype chain
// from object to (but not including) holder.
static void GenerateCheckPropertyCells(MacroAssembler* masm,
void StubCompiler::GenerateCheckPropertyCells(MacroAssembler* masm,
Handle<JSObject> object,
Handle<JSObject> holder,
Handle<Name> name,
......@@ -1373,26 +1367,6 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
}
void LoadStubCompiler::NonexistentHandlerFrontend(
Handle<JSObject> object,
Handle<JSObject> last,
Handle<Name> name,
Label* success,
Handle<GlobalObject> global) {
Label miss;
HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
if (!global.is_null()) {
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
HandlerFrontendFooter(name, success, &miss);
}
void LoadStubCompiler::GenerateLoadField(Register reg,
Handle<JSObject> holder,
PropertyIndex field,
......
......@@ -137,38 +137,34 @@ static void ProbeTable(Isolate* isolate,
}
// Helper function used to check that the dictionary doesn't contain
// the property. This function may return false negatives, so miss_label
// must always call a backup property check that is complete.
// This function is safe to call if the receiver has fast properties.
// Name must be unique and receiver must be a heap object.
static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
void StubCompiler::GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Label* miss_label,
Register receiver,
Handle<Name> name,
Register r0,
Register r1) {
Register scratch0,
Register scratch1) {
ASSERT(name->IsUniqueName());
ASSERT(!receiver.is(scratch0));
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->negative_lookups(), 1);
__ IncrementCounter(counters->negative_lookups_miss(), 1);
__ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset));
__ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
const int kInterceptorOrAccessCheckNeededMask =
(1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
// Bail out if the receiver has a named interceptor or requires access checks.
__ test_b(FieldOperand(r0, Map::kBitFieldOffset),
__ test_b(FieldOperand(scratch0, Map::kBitFieldOffset),
kInterceptorOrAccessCheckNeededMask);
__ j(not_zero, miss_label);
// Check that receiver is a JSObject.
__ CmpInstanceType(r0, FIRST_SPEC_OBJECT_TYPE);
__ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE);
__ j(below, miss_label);
// Load properties array.
Register properties = r0;
Register properties = scratch0;
__ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
// Check that the properties array is a dictionary.
......@@ -182,7 +178,7 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
&done,
properties,
name,
r1);
scratch1);
__ bind(&done);
__ DecrementCounter(counters->negative_lookups_miss(), 1);
}
......@@ -792,7 +788,7 @@ void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
static void GenerateCheckPropertyCell(MacroAssembler* masm,
void StubCompiler::GenerateCheckPropertyCell(MacroAssembler* masm,
Handle<GlobalObject> global,
Handle<Name> name,
Register scratch,
......@@ -1122,9 +1118,7 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
}
// Calls GenerateCheckPropertyCell for each global object in the prototype chain
// from object to (but not including) holder.
static void GenerateCheckPropertyCells(MacroAssembler* masm,
void StubCompiler::GenerateCheckPropertyCells(MacroAssembler* masm,
Handle<JSObject> object,
Handle<JSObject> holder,
Handle<Name> name,
......@@ -1355,26 +1349,6 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
}
void LoadStubCompiler::NonexistentHandlerFrontend(
Handle<JSObject> object,
Handle<JSObject> last,
Handle<Name> name,
Label* success,
Handle<GlobalObject> global) {
Label miss;
HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
if (!global.is_null()) {
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
HandlerFrontendFooter(name, success, &miss);
}
void LoadStubCompiler::GenerateLoadField(Register reg,
Handle<JSObject> holder,
PropertyIndex field,
......
......@@ -117,18 +117,14 @@ static void ProbeTable(Isolate* isolate,
}
// Helper function used to check that the dictionary doesn't contain
// the property. This function may return false negatives, so miss_label
// must always call a backup property check that is complete.
// This function is safe to call if the receiver has fast properties.
// Name must be unique and receiver must be a heap object.
static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
void StubCompiler::GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Label* miss_label,
Register receiver,
Handle<Name> name,
Register scratch0,
Register scratch1) {
ASSERT(name->IsUniqueName());
ASSERT(!receiver.is(scratch0));
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1);
__ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1);
......@@ -408,10 +404,7 @@ void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
}
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
static void GenerateCheckPropertyCell(MacroAssembler* masm,
void StubCompiler::GenerateCheckPropertyCell(MacroAssembler* masm,
Handle<GlobalObject> global,
Handle<Name> name,
Register scratch,
......@@ -1149,9 +1142,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
};
// Calls GenerateCheckPropertyCell for each global object in the prototype chain
// from object to (but not including) holder.
static void GenerateCheckPropertyCells(MacroAssembler* masm,
void StubCompiler::GenerateCheckPropertyCells(MacroAssembler* masm,
Handle<JSObject> object,
Handle<JSObject> holder,
Handle<Name> name,
......@@ -1364,26 +1355,6 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
}
void LoadStubCompiler::NonexistentHandlerFrontend(
Handle<JSObject> object,
Handle<JSObject> last,
Handle<Name> name,
Label* success,
Handle<GlobalObject> global) {
Label miss;
HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
if (!global.is_null()) {
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
HandlerFrontendFooter(name, success, &miss);
}
void LoadStubCompiler::GenerateLoadField(Register reg,
Handle<JSObject> holder,
PropertyIndex field,
......
......@@ -1208,6 +1208,40 @@ Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<JSObject> object,
}
void LoadStubCompiler::NonexistentHandlerFrontend(
Handle<JSObject> object,
Handle<JSObject> last,
Handle<Name> name,
Label* success,
Handle<GlobalObject> global) {
Label miss;
Register holder =
HandlerFrontendHeader(object, receiver(), last, name, &miss);
if (!last->HasFastProperties() &&
!last->IsJSGlobalObject() &&
!last->IsJSGlobalProxy()) {
if (!name->IsUniqueName()) {
ASSERT(name->IsString());
name = factory()->InternalizeString(Handle<String>::cast(name));
}
ASSERT(last->property_dictionary()->FindEntry(*name) ==
NameDictionary::kNotFound);
GenerateDictionaryNegativeLookup(masm(), &miss, holder, name,
scratch2(), scratch3());
}
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
if (!global.is_null()) {
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
HandlerFrontendFooter(name, success, &miss);
}
Handle<Code> LoadStubCompiler::CompileLoadField(
Handle<JSObject> object,
Handle<JSObject> holder,
......
......@@ -434,6 +434,18 @@ class StubCompiler BASE_EMBEDDED {
int index,
Register prototype);
// Helper function used to check that the dictionary doesn't contain
// the property. This function may return false negatives, so miss_label
// must always call a backup property check that is complete.
// This function is safe to call if the receiver has fast properties.
// Name must be unique and receiver must be a heap object.
static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Label* miss_label,
Register receiver,
Handle<Name> name,
Register r0,
Register r1);
// Generates prototype loading code that uses the objects from the
// context we were in when this function was called. If the context
// has changed, a jump to miss is performed. This ties the generated
......@@ -469,6 +481,24 @@ class StubCompiler BASE_EMBEDDED {
Register scratch2,
Label* miss_label);
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
static void GenerateCheckPropertyCell(MacroAssembler* masm,
Handle<GlobalObject> global,
Handle<Name> name,
Register scratch,
Label* miss);
// Calls GenerateCheckPropertyCell for each global object in the prototype
// chain from object to (but not including) holder.
static void GenerateCheckPropertyCells(MacroAssembler* masm,
Handle<JSObject> object,
Handle<JSObject> holder,
Handle<Name> name,
Register scratch,
Label* miss);
static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name);
// Generates code that verifies that the property holder has not changed
......
......@@ -107,38 +107,34 @@ static void ProbeTable(Isolate* isolate,
}
// Helper function used to check that the dictionary doesn't contain
// the property. This function may return false negatives, so miss_label
// must always call a backup property check that is complete.
// This function is safe to call if the receiver has fast properties.
// Name must be unique and receiver must be a heap object.
static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
void StubCompiler::GenerateDictionaryNegativeLookup(MacroAssembler* masm,
Label* miss_label,
Register receiver,
Handle<Name> name,
Register r0,
Register r1) {
Register scratch0,
Register scratch1) {
ASSERT(name->IsUniqueName());
ASSERT(!receiver.is(scratch0));
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->negative_lookups(), 1);
__ IncrementCounter(counters->negative_lookups_miss(), 1);
__ movq(r0, FieldOperand(receiver, HeapObject::kMapOffset));
__ movq(scratch0, FieldOperand(receiver, HeapObject::kMapOffset));
const int kInterceptorOrAccessCheckNeededMask =
(1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
// Bail out if the receiver has a named interceptor or requires access checks.
__ testb(FieldOperand(r0, Map::kBitFieldOffset),
__ testb(FieldOperand(scratch0, Map::kBitFieldOffset),
Immediate(kInterceptorOrAccessCheckNeededMask));
__ j(not_zero, miss_label);
// Check that receiver is a JSObject.
__ CmpInstanceType(r0, FIRST_SPEC_OBJECT_TYPE);
__ CmpInstanceType(scratch0, FIRST_SPEC_OBJECT_TYPE);
__ j(below, miss_label);
// Load properties array.
Register properties = r0;
Register properties = scratch0;
__ movq(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
// Check that the properties array is a dictionary.
......@@ -152,7 +148,7 @@ static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
&done,
properties,
name,
r1);
scratch1);
__ bind(&done);
__ DecrementCounter(counters->negative_lookups_miss(), 1);
}
......@@ -777,10 +773,7 @@ void StoreStubCompiler::GenerateRestoreName(MacroAssembler* masm,
}
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
static void GenerateCheckPropertyCell(MacroAssembler* masm,
void StubCompiler::GenerateCheckPropertyCell(MacroAssembler* masm,
Handle<GlobalObject> global,
Handle<Name> name,
Register scratch,
......@@ -1054,9 +1047,7 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
}
// Calls GenerateCheckPropertyCell for each global object in the prototype chain
// from object to (but not including) holder.
static void GenerateCheckPropertyCells(MacroAssembler* masm,
void StubCompiler::GenerateCheckPropertyCells(MacroAssembler* masm,
Handle<JSObject> object,
Handle<JSObject> holder,
Handle<Name> name,
......@@ -1282,26 +1273,6 @@ Register LoadStubCompiler::CallbackHandlerFrontend(
}
void LoadStubCompiler::NonexistentHandlerFrontend(
Handle<JSObject> object,
Handle<JSObject> last,
Handle<Name> name,
Label* success,
Handle<GlobalObject> global) {
Label miss;
HandlerFrontendHeader(object, receiver(), last, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
if (!global.is_null()) {
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
HandlerFrontendFooter(name, success, &miss);
}
void LoadStubCompiler::GenerateLoadField(Register reg,
Handle<JSObject> holder,
PropertyIndex field,
......
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function test(expected, holder) {
assertEquals(expected, holder.property);
}
var holder = {}
holder.__proto__ = null;
holder.property = "foo";
delete holder.property;
test(undefined, holder);
test(undefined, holder);
test(undefined, holder);
holder.property = "bar";
test("bar", holder);
test("bar", holder);
// Now the same thing with a nontrivial prototype chain.
function test2(expected, holder) {
assertEquals(expected, holder.prop2);
}
var holder2 = {}
holder2.prop2 = "foo";
holder2.__proto__ = null;
function Receiver() {}
Receiver.prototype = holder2;
var rec2 = new Receiver();
delete holder2.prop2;
test2(undefined, rec2);
test2(undefined, rec2);
test2(undefined, rec2);
holder2.prop2 = "bar";
test2("bar", rec2);
test2("bar", rec2);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment