Index: src/builtins/builtins-promise.cc |
diff --git a/src/builtins/builtins-promise.cc b/src/builtins/builtins-promise.cc |
index 345625d6d098d09eeb7686658803da7bdbcfa046..351cbfe5cc7d72e1c2dfc2a40ec7056589c0b79b 100644 |
--- a/src/builtins/builtins-promise.cc |
+++ b/src/builtins/builtins-promise.cc |
@@ -904,6 +904,50 @@ void PromiseBuiltinsAssembler::PromiseFulfill( |
} |
} |
+void PromiseBuiltinsAssembler::BranchIfAccessCheckFailed( |
+ Node* context, Node* promise_constructor, Node* executor, |
+ Label* if_noaccess) { |
+ Variable var_executor(this, MachineRepresentation::kTagged); |
+ var_executor.Bind(executor); |
+ Label has_access(this), call_runtime(this, Label::kDeferred); |
+ |
+ // If executor is a bound function, load the bound function until we've |
+ // reached an actual function. |
+ Label found_function(this), loop_over_bound_function(this, &var_executor); |
+ Goto(&loop_over_bound_function); |
+ Bind(&loop_over_bound_function); |
gsathya
2017/01/11 17:27:31
i wonder if its better to duplicate the IsJSFuncti
jochen (gone - plz use gerrit)
2017/01/11 18:09:57
afaik that shouldn't make that much of a differenc
Igor Sheludko
2017/01/12 08:31:11
I think it's fine to avoid marking the block as de
|
+ { |
+ GotoIf(IsJSFunction(var_executor.value()), &found_function); |
+ GotoUnless(IsJSBoundFunction(var_executor.value()), &call_runtime); |
Igor Sheludko
2017/01/12 08:31:11
Here you are loading map and then instance type se
|
+ var_executor.Bind(LoadObjectField( |
+ var_executor.value(), JSBoundFunction::kBoundTargetFunctionOffset)); |
+ Goto(&loop_over_bound_function); |
+ } |
+ |
+ // Load the context from the function and compare it to the Promise |
+ // constructor's context. If they match, everything is fine, otherwise, bail |
+ // out to the runtime. |
+ Bind(&found_function); |
+ { |
+ Node* native_context = LoadNativeContext(context); |
gsathya
2017/01/11 17:27:31
this can be an argument to this function, no need
jochen (gone - plz use gerrit)
2017/01/11 18:09:57
done
|
+ Node* function_context = |
+ LoadObjectField(var_executor.value(), JSFunction::kContextOffset); |
+ Node* native_function_context = LoadNativeContext(function_context); |
+ Branch(WordEqual(native_context, native_function_context), &has_access, |
+ &call_runtime); |
+ } |
+ |
+ Bind(&call_runtime); |
+ { |
+ Branch(WordEqual(CallRuntime(Runtime::kAllowDynamicFunction, context, |
+ promise_constructor), |
+ BooleanConstant(true)), |
+ &has_access, if_noaccess); |
+ } |
+ |
+ Bind(&has_access); |
+} |
+ |
// ES#sec-promise-reject-functions |
// Promise Reject Functions |
TF_BUILTIN(PromiseRejectClosure, PromiseBuiltinsAssembler) { |
@@ -961,7 +1005,9 @@ TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) { |
Node* const is_debug_active = IsDebugActive(); |
Label if_targetisnotmodified(this), |
if_targetismodified(this, Label::kDeferred), run_executor(this), |
- debug_push(this); |
+ debug_push(this), if_noaccess(this, Label::kDeferred); |
+ |
+ BranchIfAccessCheckFailed(context, promise_fun, executor, &if_noaccess); |
Branch(WordEqual(promise_fun, new_target), &if_targetisnotmodified, |
&if_targetismodified); |
@@ -1046,6 +1092,15 @@ TF_BUILTIN(PromiseConstructor, PromiseBuiltinsAssembler) { |
CallRuntime(Runtime::kThrowTypeError, context, message_id, executor); |
Return(UndefinedConstant()); // Never reached. |
} |
+ |
+ // Silently fail if the stack looks fishy. |
+ Bind(&if_noaccess); |
+ { |
+ Node* const counter_id = |
+ SmiConstant(v8::Isolate::kPromiseConstructorReturnedUndefined); |
+ CallRuntime(Runtime::kCountUsage, context, counter_id); |
+ Return(UndefinedConstant()); |
+ } |
} |
TF_BUILTIN(PromiseInternalConstructor, PromiseBuiltinsAssembler) { |