Implement inline %_IsJSProxy() for full codegen and Hydrogen

Saving a runtime call for many builtin functions.

R=ishell@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24636 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
jkummerow@chromium.org 2014-10-15 13:26:43 +00:00
parent ad80a80a8b
commit c9ae9b3b70
9 changed files with 143 additions and 18 deletions

View File

@ -3440,6 +3440,32 @@ void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
}
void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
VisitForAccumulatorValue(args->at(0));
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
&if_false, &fall_through);
__ JumpIfSmi(r0, if_false);
Register map = r1;
Register type_reg = r2;
__ ldr(map, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
__ sub(type_reg, type_reg, Operand(FIRST_JS_PROXY_TYPE));
__ cmp(type_reg, Operand(LAST_JS_PROXY_TYPE - FIRST_JS_PROXY_TYPE));
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Split(ls, if_true, if_false, fall_through);
context()->Plug(if_true, if_false);
}
void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
DCHECK(expr->arguments()->length() == 0);

View File

@ -3117,6 +3117,32 @@ void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
}
void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
VisitForAccumulatorValue(args->at(0));
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
&if_false, &fall_through);
__ JumpIfSmi(x0, if_false);
Register map = x10;
Register type_reg = x11;
__ Ldr(map, FieldMemOperand(x0, HeapObject::kMapOffset));
__ Ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
__ Sub(type_reg, type_reg, Operand(FIRST_JS_PROXY_TYPE));
__ Cmp(type_reg, Operand(LAST_JS_PROXY_TYPE - FIRST_JS_PROXY_TYPE));
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Split(ls, if_true, if_false, fall_through);
context()->Plug(if_true, if_false);
}
void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
DCHECK(expr->arguments()->length() == 0);

View File

@ -11538,6 +11538,29 @@ void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) {
}
void HOptimizedGraphBuilder::GenerateIsJSProxy(CallRuntime* call) {
DCHECK(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* value = Pop();
HIfContinuation continuation;
IfBuilder if_proxy(this);
HValue* smicheck = if_proxy.IfNot<HIsSmiAndBranch>(value);
if_proxy.And();
HValue* map = Add<HLoadNamedField>(value, smicheck, HObjectAccess::ForMap());
HValue* instance_type = Add<HLoadNamedField>(
map, static_cast<HValue*>(NULL), HObjectAccess::ForMapInstanceType());
if_proxy.If<HCompareNumericAndBranch>(
instance_type, Add<HConstant>(FIRST_JS_PROXY_TYPE), Token::GTE);
if_proxy.And();
if_proxy.If<HCompareNumericAndBranch>(
instance_type, Add<HConstant>(LAST_JS_PROXY_TYPE), Token::LTE);
if_proxy.CaptureContinuation(&continuation);
return ast_context()->ReturnContinuation(&continuation, call->id());
}
void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi);
}

View File

@ -3338,6 +3338,31 @@ void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
}
void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
VisitForAccumulatorValue(args->at(0));
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
&if_false, &fall_through);
__ JumpIfSmi(eax, if_false);
Register map = ebx;
__ mov(map, FieldOperand(eax, HeapObject::kMapOffset));
__ CmpInstanceType(map, FIRST_JS_PROXY_TYPE);
__ j(less, if_false);
__ CmpInstanceType(map, LAST_JS_PROXY_TYPE);
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Split(less_equal, if_true, if_false, fall_through);
context()->Plug(if_true, if_false);
}
void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
DCHECK(expr->arguments()->length() == 0);

View File

@ -194,9 +194,9 @@ function ObserverIsActive(observer, objectInfo) {
function ObjectInfoGetOrCreate(object) {
var objectInfo = ObjectInfoGet(object);
if (IS_UNDEFINED(objectInfo)) {
if (!%IsJSProxy(object))
if (!%_IsJSProxy(object)) {
%SetIsObserved(object);
}
objectInfo = {
object: object,
changeObservers: null,

View File

@ -35,10 +35,10 @@ RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) {
}
RUNTIME_FUNCTION(Runtime_IsJSProxy) {
RUNTIME_FUNCTION(RuntimeReference_IsJSProxy) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
CONVERT_ARG_CHECKED(Object, obj, 0);
return isolate->heap()->ToBoolean(obj->IsJSProxy());
}

View File

@ -291,7 +291,6 @@ namespace internal {
/* Harmony proxies */ \
F(CreateJSProxy, 2, 1) \
F(CreateJSFunctionProxy, 4, 1) \
F(IsJSProxy, 1, 1) \
F(IsJSFunctionProxy, 1, 1) \
F(GetHandler, 1, 1) \
F(GetCallTrap, 1, 1) \
@ -668,6 +667,7 @@ namespace internal {
F(IsNonNegativeSmi, 1, 1) \
F(IsArray, 1, 1) \
F(IsRegExp, 1, 1) \
F(IsJSProxy, 1, 1) \
F(IsConstructCall, 0, 1) \
F(CallFunction, -1 /* receiver + n args + function */, 1) \
F(ArgumentsLength, 0, 1) \

View File

@ -238,7 +238,7 @@ function ObjectValueOf() {
// ECMA-262 - 15.2.4.5
function ObjectHasOwnProperty(V) {
if (%IsJSProxy(this)) {
if (%_IsJSProxy(this)) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(V)) return false;
@ -260,7 +260,7 @@ function ObjectIsPrototypeOf(V) {
// ECMA-262 - 15.2.4.6
function ObjectPropertyIsEnumerable(V) {
var P = ToName(V);
if (%IsJSProxy(this)) {
if (%_IsJSProxy(this)) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(V)) return false;
@ -326,7 +326,7 @@ function ObjectLookupSetter(name) {
function ObjectKeys(obj) {
obj = ToObject(obj);
if (%IsJSProxy(obj)) {
if (%_IsJSProxy(obj)) {
var handler = %GetHandler(obj);
var names = CallTrap0(handler, "keys", DerivedKeysTrap);
return ToNameArray(names, "keys", false);
@ -623,7 +623,7 @@ function CallTrap2(handler, name, defaultTrap, x, y) {
// ES5 section 8.12.1.
function GetOwnPropertyJS(obj, v) {
var p = ToName(v);
if (%IsJSProxy(obj)) {
if (%_IsJSProxy(obj)) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(v)) return UNDEFINED;
@ -963,7 +963,7 @@ function DefineArrayProperty(obj, p, desc, should_throw) {
// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
function DefineOwnProperty(obj, p, desc, should_throw) {
if (%IsJSProxy(obj)) {
if (%_IsJSProxy(obj)) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(p)) return false;
@ -1111,7 +1111,7 @@ function ObjectGetOwnPropertyNames(obj) {
throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
}
// Special handling for proxies.
if (%IsJSProxy(obj)) {
if (%_IsJSProxy(obj)) {
var handler = %GetHandler(obj);
var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED);
return ToNameArray(names, "getOwnPropertyNames", false);
@ -1139,7 +1139,7 @@ function ObjectDefineProperty(obj, p, attributes) {
throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
}
var name = ToName(p);
if (%IsJSProxy(obj)) {
if (%_IsJSProxy(obj)) {
// Clone the attributes object for protection.
// TODO(rossberg): not spec'ed yet, so not sure if this should involve
// non-own properties as it does (or non-enumerable ones, as it doesn't?).
@ -1248,7 +1248,7 @@ function ObjectSeal(obj) {
if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("called_on_non_object", ["Object.seal"]);
}
if (%IsJSProxy(obj)) {
if (%_IsJSProxy(obj)) {
ProxyFix(obj);
}
var names = ObjectGetOwnPropertyNames(obj);
@ -1270,7 +1270,7 @@ function ObjectFreezeJS(obj) {
if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
}
var isProxy = %IsJSProxy(obj);
var isProxy = %_IsJSProxy(obj);
if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
if (isProxy) {
ProxyFix(obj);
@ -1300,7 +1300,7 @@ function ObjectPreventExtension(obj) {
if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
}
if (%IsJSProxy(obj)) {
if (%_IsJSProxy(obj)) {
ProxyFix(obj);
}
%PreventExtensions(obj);
@ -1313,7 +1313,7 @@ function ObjectIsSealed(obj) {
if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
}
if (%IsJSProxy(obj)) {
if (%_IsJSProxy(obj)) {
return false;
}
if (%IsExtensible(obj)) {
@ -1336,7 +1336,7 @@ function ObjectIsFrozen(obj) {
if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
}
if (%IsJSProxy(obj)) {
if (%_IsJSProxy(obj)) {
return false;
}
if (%IsExtensible(obj)) {
@ -1358,7 +1358,7 @@ function ObjectIsExtensible(obj) {
if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
}
if (%IsJSProxy(obj)) {
if (%_IsJSProxy(obj)) {
return true;
}
return %IsExtensible(obj);

View File

@ -3330,6 +3330,31 @@ void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
}
void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
DCHECK(args->length() == 1);
VisitForAccumulatorValue(args->at(0));
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
&if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
Register map = rbx;
__ movp(map, FieldOperand(rax, HeapObject::kMapOffset));
__ CmpInstanceType(map, FIRST_JS_PROXY_TYPE);
__ j(less, if_false);
__ CmpInstanceType(map, LAST_JS_PROXY_TYPE);
PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
Split(less_equal, if_true, if_false, fall_through);
context()->Plug(if_true, if_false);
}
void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
DCHECK(expr->arguments()->length() == 0);