Optimize GetPrototype
This introduces Hydrogen for %_GetPrototype. The code falls back on runtime if the object needs access checks or if its prototype is a hidden prototype. BUG=None LOG=Y R=dslomov@chromium.org Review URL: https://codereview.chromium.org/756423006 Cr-Commit-Position: refs/heads/master@{#25694}
This commit is contained in:
parent
761891d201
commit
c8c7395644
@ -984,7 +984,7 @@ function ArraySort(comparefn) {
|
||||
// of a prototype property.
|
||||
var CopyFromPrototype = function CopyFromPrototype(obj, length) {
|
||||
var max = 0;
|
||||
for (var proto = %GetPrototype(obj); proto; proto = %GetPrototype(proto)) {
|
||||
for (var proto = %_GetPrototype(obj); proto; proto = %_GetPrototype(proto)) {
|
||||
var indices = %GetArrayKeys(proto, length);
|
||||
if (IS_NUMBER(indices)) {
|
||||
// It's an interval.
|
||||
@ -1013,7 +1013,7 @@ function ArraySort(comparefn) {
|
||||
// where a prototype of obj has an element. I.e., shadow all prototype
|
||||
// elements in that range.
|
||||
var ShadowPrototypeElements = function(obj, from, to) {
|
||||
for (var proto = %GetPrototype(obj); proto; proto = %GetPrototype(proto)) {
|
||||
for (var proto = %_GetPrototype(obj); proto; proto = %_GetPrototype(proto)) {
|
||||
var indices = %GetArrayKeys(proto, to);
|
||||
if (IS_NUMBER(indices)) {
|
||||
// It's an interval.
|
||||
@ -1081,7 +1081,7 @@ function ArraySort(comparefn) {
|
||||
}
|
||||
for (i = length - num_holes; i < length; i++) {
|
||||
// For compatability with Webkit, do not expose elements in the prototype.
|
||||
if (i in %GetPrototype(obj)) {
|
||||
if (i in %_GetPrototype(obj)) {
|
||||
obj[i] = UNDEFINED;
|
||||
} else {
|
||||
delete obj[i];
|
||||
|
@ -6179,6 +6179,10 @@ class HObjectAccess FINAL {
|
||||
return HObjectAccess(kMaps, JSObject::kMapOffset);
|
||||
}
|
||||
|
||||
static HObjectAccess ForPrototype() {
|
||||
return HObjectAccess(kMaps, Map::kPrototypeOffset);
|
||||
}
|
||||
|
||||
static HObjectAccess ForMapAsInteger32() {
|
||||
return HObjectAccess(kMaps, JSObject::kMapOffset,
|
||||
Representation::Integer32());
|
||||
|
@ -12390,6 +12390,54 @@ void HOptimizedGraphBuilder::GenerateDebugIsActive(CallRuntime* call) {
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateGetPrototype(CallRuntime* call) {
|
||||
DCHECK(call->arguments()->length() == 1);
|
||||
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
||||
HValue* object = Pop();
|
||||
|
||||
NoObservableSideEffectsScope no_effects(this);
|
||||
|
||||
HValue* map = Add<HLoadNamedField>(object, static_cast<HValue*>(NULL),
|
||||
HObjectAccess::ForMap());
|
||||
HValue* bit_field = Add<HLoadNamedField>(map, static_cast<HValue*>(NULL),
|
||||
HObjectAccess::ForMapBitField());
|
||||
HValue* is_access_check_needed_mask =
|
||||
Add<HConstant>(1 << Map::kIsAccessCheckNeeded);
|
||||
HValue* is_access_check_needed_test = AddUncasted<HBitwise>(
|
||||
Token::BIT_AND, bit_field, is_access_check_needed_mask);
|
||||
|
||||
HValue* proto = Add<HLoadNamedField>(map, static_cast<HValue*>(NULL),
|
||||
HObjectAccess::ForPrototype());
|
||||
HValue* proto_map = Add<HLoadNamedField>(proto, static_cast<HValue*>(NULL),
|
||||
HObjectAccess::ForMap());
|
||||
HValue* proto_bit_field = Add<HLoadNamedField>(
|
||||
proto_map, static_cast<HValue*>(NULL), HObjectAccess::ForMapBitField());
|
||||
HValue* is_hidden_prototype_mask =
|
||||
Add<HConstant>(1 << Map::kIsHiddenPrototype);
|
||||
HValue* is_hidden_prototype_test = AddUncasted<HBitwise>(
|
||||
Token::BIT_AND, proto_bit_field, is_hidden_prototype_mask);
|
||||
|
||||
{
|
||||
IfBuilder needs_runtime(this);
|
||||
needs_runtime.If<HCompareNumericAndBranch>(
|
||||
is_access_check_needed_test, graph()->GetConstant0(), Token::NE);
|
||||
needs_runtime.OrIf<HCompareNumericAndBranch>(
|
||||
is_hidden_prototype_test, graph()->GetConstant0(), Token::NE);
|
||||
|
||||
needs_runtime.Then();
|
||||
{
|
||||
Add<HPushArguments>(object);
|
||||
Push(Add<HCallRuntime>(
|
||||
call->name(), Runtime::FunctionForId(Runtime::kGetPrototype), 1));
|
||||
}
|
||||
|
||||
needs_runtime.Else();
|
||||
Push(proto);
|
||||
}
|
||||
return ast_context()->ReturnValue(Pop());
|
||||
}
|
||||
|
||||
|
||||
#undef CHECK_BAILOUT
|
||||
#undef CHECK_ALIVE
|
||||
|
||||
|
@ -1151,7 +1151,7 @@ var StackTraceGetter = function() {
|
||||
if (IS_UNDEFINED(stack_trace)) {
|
||||
// Neither formatted nor structured stack trace available.
|
||||
// Look further up the prototype chain.
|
||||
holder = %GetPrototype(holder);
|
||||
holder = %_GetPrototype(holder);
|
||||
continue;
|
||||
}
|
||||
formatted_stack_trace = FormatStackTrace(holder, stack_trace);
|
||||
@ -1255,7 +1255,7 @@ function GetPropertyWithoutInvokingMonkeyGetters(error, name) {
|
||||
var current = error;
|
||||
// Climb the prototype chain until we find the holder.
|
||||
while (current && !%HasOwnProperty(current, name)) {
|
||||
current = %GetPrototype(current);
|
||||
current = %_GetPrototype(current);
|
||||
}
|
||||
if (IS_NULL(current)) return UNDEFINED;
|
||||
if (!IS_OBJECT(current)) return error[name];
|
||||
|
@ -45,7 +45,6 @@ namespace internal {
|
||||
F(IsSloppyModeFunction, 1, 1) \
|
||||
F(GetDefaultReceiver, 1, 1) \
|
||||
\
|
||||
F(GetPrototype, 1, 1) \
|
||||
F(SetPrototype, 2, 1) \
|
||||
F(InternalSetPrototype, 2, 1) \
|
||||
F(IsInPrototypeChain, 2, 1) \
|
||||
@ -733,7 +732,8 @@ namespace internal {
|
||||
F(SetGetSize, 1, 1) \
|
||||
F(SetHas, 2, 1) \
|
||||
/* Arrays */ \
|
||||
F(HasFastPackedElements, 1, 1)
|
||||
F(HasFastPackedElements, 1, 1) \
|
||||
F(GetPrototype, 1, 1)
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -973,7 +973,7 @@ function ObjectGetPrototypeOf(obj) {
|
||||
if (!IS_SPEC_OBJECT(obj)) {
|
||||
throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
|
||||
}
|
||||
return %GetPrototype(obj);
|
||||
return %_GetPrototype(obj);
|
||||
}
|
||||
|
||||
// ES6 section 19.1.2.19.
|
||||
@ -1361,7 +1361,7 @@ function ObjectIs(obj1, obj2) {
|
||||
|
||||
// ECMA-262, Edition 6, section B.2.2.1.1
|
||||
function ObjectGetProto() {
|
||||
return %GetPrototype(ToObject(this));
|
||||
return %_GetPrototype(ToObject(this));
|
||||
}
|
||||
|
||||
|
||||
|
@ -24518,3 +24518,56 @@ TEST(TurboAsmDisablesNeuter) {
|
||||
result = CompileRun(store).As<v8::ArrayBuffer>();
|
||||
CHECK_EQ(should_be_neuterable, result->IsNeuterable());
|
||||
}
|
||||
|
||||
|
||||
TEST(GetPrototypeAccessControl) {
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
LocalContext env;
|
||||
|
||||
v8::Handle<v8::ObjectTemplate> obj_template =
|
||||
v8::ObjectTemplate::New(isolate);
|
||||
obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
|
||||
BlockEverythingIndexed);
|
||||
|
||||
env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
|
||||
|
||||
{
|
||||
v8::TryCatch try_catch;
|
||||
CompileRun(
|
||||
"function f() { %_GetPrototype(prohibited); }"
|
||||
"%OptimizeFunctionOnNextCall(f);"
|
||||
"f();");
|
||||
CHECK(try_catch.HasCaught());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(GetPrototypeHidden) {
|
||||
i::FLAG_allow_natives_syntax = true;
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
LocalContext env;
|
||||
|
||||
Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
|
||||
t->SetHiddenPrototype(true);
|
||||
Handle<Object> proto = t->GetFunction()->NewInstance();
|
||||
Handle<Object> object = Object::New(isolate);
|
||||
Handle<Object> proto2 = Object::New(isolate);
|
||||
object->SetPrototype(proto);
|
||||
proto->SetPrototype(proto2);
|
||||
|
||||
env->Global()->Set(v8_str("object"), object);
|
||||
env->Global()->Set(v8_str("proto"), proto);
|
||||
env->Global()->Set(v8_str("proto2"), proto2);
|
||||
|
||||
v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
|
||||
CHECK(result->Equals(proto2));
|
||||
|
||||
result = CompileRun(
|
||||
"function f() { return %_GetPrototype(object); }"
|
||||
"%OptimizeFunctionOnNextCall(f);"
|
||||
"f()");
|
||||
CHECK(result->Equals(proto2));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user