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:
parent
ad80a80a8b
commit
c9ae9b3b70
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user