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
parent ad80a80a
...@@ -3440,6 +3440,32 @@ void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { ...@@ -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) { void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
DCHECK(expr->arguments()->length() == 0); DCHECK(expr->arguments()->length() == 0);
......
...@@ -3117,6 +3117,32 @@ void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { ...@@ -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) { void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
DCHECK(expr->arguments()->length() == 0); DCHECK(expr->arguments()->length() == 0);
......
...@@ -11538,6 +11538,29 @@ void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) { ...@@ -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) { void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) {
return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi); return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi);
} }
......
...@@ -3338,6 +3338,31 @@ void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { ...@@ -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) { void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
DCHECK(expr->arguments()->length() == 0); DCHECK(expr->arguments()->length() == 0);
......
...@@ -194,9 +194,9 @@ function ObserverIsActive(observer, objectInfo) { ...@@ -194,9 +194,9 @@ function ObserverIsActive(observer, objectInfo) {
function ObjectInfoGetOrCreate(object) { function ObjectInfoGetOrCreate(object) {
var objectInfo = ObjectInfoGet(object); var objectInfo = ObjectInfoGet(object);
if (IS_UNDEFINED(objectInfo)) { if (IS_UNDEFINED(objectInfo)) {
if (!%IsJSProxy(object)) if (!%_IsJSProxy(object)) {
%SetIsObserved(object); %SetIsObserved(object);
}
objectInfo = { objectInfo = {
object: object, object: object,
changeObservers: null, changeObservers: null,
......
...@@ -35,10 +35,10 @@ RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) { ...@@ -35,10 +35,10 @@ RUNTIME_FUNCTION(Runtime_CreateJSFunctionProxy) {
} }
RUNTIME_FUNCTION(Runtime_IsJSProxy) { RUNTIME_FUNCTION(RuntimeReference_IsJSProxy) {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
DCHECK(args.length() == 1); DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0); CONVERT_ARG_CHECKED(Object, obj, 0);
return isolate->heap()->ToBoolean(obj->IsJSProxy()); return isolate->heap()->ToBoolean(obj->IsJSProxy());
} }
......
...@@ -291,7 +291,6 @@ namespace internal { ...@@ -291,7 +291,6 @@ namespace internal {
/* Harmony proxies */ \ /* Harmony proxies */ \
F(CreateJSProxy, 2, 1) \ F(CreateJSProxy, 2, 1) \
F(CreateJSFunctionProxy, 4, 1) \ F(CreateJSFunctionProxy, 4, 1) \
F(IsJSProxy, 1, 1) \
F(IsJSFunctionProxy, 1, 1) \ F(IsJSFunctionProxy, 1, 1) \
F(GetHandler, 1, 1) \ F(GetHandler, 1, 1) \
F(GetCallTrap, 1, 1) \ F(GetCallTrap, 1, 1) \
...@@ -668,6 +667,7 @@ namespace internal { ...@@ -668,6 +667,7 @@ namespace internal {
F(IsNonNegativeSmi, 1, 1) \ F(IsNonNegativeSmi, 1, 1) \
F(IsArray, 1, 1) \ F(IsArray, 1, 1) \
F(IsRegExp, 1, 1) \ F(IsRegExp, 1, 1) \
F(IsJSProxy, 1, 1) \
F(IsConstructCall, 0, 1) \ F(IsConstructCall, 0, 1) \
F(CallFunction, -1 /* receiver + n args + function */, 1) \ F(CallFunction, -1 /* receiver + n args + function */, 1) \
F(ArgumentsLength, 0, 1) \ F(ArgumentsLength, 0, 1) \
......
...@@ -238,7 +238,7 @@ function ObjectValueOf() { ...@@ -238,7 +238,7 @@ function ObjectValueOf() {
// ECMA-262 - 15.2.4.5 // ECMA-262 - 15.2.4.5
function ObjectHasOwnProperty(V) { function ObjectHasOwnProperty(V) {
if (%IsJSProxy(this)) { if (%_IsJSProxy(this)) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies. // TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(V)) return false; if (IS_SYMBOL(V)) return false;
...@@ -260,7 +260,7 @@ function ObjectIsPrototypeOf(V) { ...@@ -260,7 +260,7 @@ function ObjectIsPrototypeOf(V) {
// ECMA-262 - 15.2.4.6 // ECMA-262 - 15.2.4.6
function ObjectPropertyIsEnumerable(V) { function ObjectPropertyIsEnumerable(V) {
var P = ToName(V); var P = ToName(V);
if (%IsJSProxy(this)) { if (%_IsJSProxy(this)) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies. // TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(V)) return false; if (IS_SYMBOL(V)) return false;
...@@ -326,7 +326,7 @@ function ObjectLookupSetter(name) { ...@@ -326,7 +326,7 @@ function ObjectLookupSetter(name) {
function ObjectKeys(obj) { function ObjectKeys(obj) {
obj = ToObject(obj); obj = ToObject(obj);
if (%IsJSProxy(obj)) { if (%_IsJSProxy(obj)) {
var handler = %GetHandler(obj); var handler = %GetHandler(obj);
var names = CallTrap0(handler, "keys", DerivedKeysTrap); var names = CallTrap0(handler, "keys", DerivedKeysTrap);
return ToNameArray(names, "keys", false); return ToNameArray(names, "keys", false);
...@@ -623,7 +623,7 @@ function CallTrap2(handler, name, defaultTrap, x, y) { ...@@ -623,7 +623,7 @@ function CallTrap2(handler, name, defaultTrap, x, y) {
// ES5 section 8.12.1. // ES5 section 8.12.1.
function GetOwnPropertyJS(obj, v) { function GetOwnPropertyJS(obj, v) {
var p = ToName(v); var p = ToName(v);
if (%IsJSProxy(obj)) { if (%_IsJSProxy(obj)) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies. // TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(v)) return UNDEFINED; if (IS_SYMBOL(v)) return UNDEFINED;
...@@ -963,7 +963,7 @@ function DefineArrayProperty(obj, p, desc, should_throw) { ...@@ -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. // ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
function DefineOwnProperty(obj, p, desc, should_throw) { 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. // TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(p)) return false; if (IS_SYMBOL(p)) return false;
...@@ -1111,7 +1111,7 @@ function ObjectGetOwnPropertyNames(obj) { ...@@ -1111,7 +1111,7 @@ function ObjectGetOwnPropertyNames(obj) {
throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]); throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
} }
// Special handling for proxies. // Special handling for proxies.
if (%IsJSProxy(obj)) { if (%_IsJSProxy(obj)) {
var handler = %GetHandler(obj); var handler = %GetHandler(obj);
var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED); var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED);
return ToNameArray(names, "getOwnPropertyNames", false); return ToNameArray(names, "getOwnPropertyNames", false);
...@@ -1139,7 +1139,7 @@ function ObjectDefineProperty(obj, p, attributes) { ...@@ -1139,7 +1139,7 @@ function ObjectDefineProperty(obj, p, attributes) {
throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]); throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
} }
var name = ToName(p); var name = ToName(p);
if (%IsJSProxy(obj)) { if (%_IsJSProxy(obj)) {
// Clone the attributes object for protection. // Clone the attributes object for protection.
// TODO(rossberg): not spec'ed yet, so not sure if this should involve // 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?). // non-own properties as it does (or non-enumerable ones, as it doesn't?).
...@@ -1248,7 +1248,7 @@ function ObjectSeal(obj) { ...@@ -1248,7 +1248,7 @@ function ObjectSeal(obj) {
if (!IS_SPEC_OBJECT(obj)) { if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("called_on_non_object", ["Object.seal"]); throw MakeTypeError("called_on_non_object", ["Object.seal"]);
} }
if (%IsJSProxy(obj)) { if (%_IsJSProxy(obj)) {
ProxyFix(obj); ProxyFix(obj);
} }
var names = ObjectGetOwnPropertyNames(obj); var names = ObjectGetOwnPropertyNames(obj);
...@@ -1270,7 +1270,7 @@ function ObjectFreezeJS(obj) { ...@@ -1270,7 +1270,7 @@ function ObjectFreezeJS(obj) {
if (!IS_SPEC_OBJECT(obj)) { if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("called_on_non_object", ["Object.freeze"]); throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
} }
var isProxy = %IsJSProxy(obj); var isProxy = %_IsJSProxy(obj);
if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) { if (isProxy || %HasSloppyArgumentsElements(obj) || %IsObserved(obj)) {
if (isProxy) { if (isProxy) {
ProxyFix(obj); ProxyFix(obj);
...@@ -1300,7 +1300,7 @@ function ObjectPreventExtension(obj) { ...@@ -1300,7 +1300,7 @@ function ObjectPreventExtension(obj) {
if (!IS_SPEC_OBJECT(obj)) { if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]); throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
} }
if (%IsJSProxy(obj)) { if (%_IsJSProxy(obj)) {
ProxyFix(obj); ProxyFix(obj);
} }
%PreventExtensions(obj); %PreventExtensions(obj);
...@@ -1313,7 +1313,7 @@ function ObjectIsSealed(obj) { ...@@ -1313,7 +1313,7 @@ function ObjectIsSealed(obj) {
if (!IS_SPEC_OBJECT(obj)) { if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("called_on_non_object", ["Object.isSealed"]); throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
} }
if (%IsJSProxy(obj)) { if (%_IsJSProxy(obj)) {
return false; return false;
} }
if (%IsExtensible(obj)) { if (%IsExtensible(obj)) {
...@@ -1336,7 +1336,7 @@ function ObjectIsFrozen(obj) { ...@@ -1336,7 +1336,7 @@ function ObjectIsFrozen(obj) {
if (!IS_SPEC_OBJECT(obj)) { if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]); throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
} }
if (%IsJSProxy(obj)) { if (%_IsJSProxy(obj)) {
return false; return false;
} }
if (%IsExtensible(obj)) { if (%IsExtensible(obj)) {
...@@ -1358,7 +1358,7 @@ function ObjectIsExtensible(obj) { ...@@ -1358,7 +1358,7 @@ function ObjectIsExtensible(obj) {
if (!IS_SPEC_OBJECT(obj)) { if (!IS_SPEC_OBJECT(obj)) {
throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]); throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
} }
if (%IsJSProxy(obj)) { if (%_IsJSProxy(obj)) {
return true; return true;
} }
return %IsExtensible(obj); return %IsExtensible(obj);
......
...@@ -3330,6 +3330,31 @@ void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) { ...@@ -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) { void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
DCHECK(expr->arguments()->length() == 0); DCHECK(expr->arguments()->length() == 0);
......
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