Home | History | Annotate | Download | only in compiler
      1 // Copyright 2015 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/compiler/js-call-reducer.h"
      6 
      7 #include "src/compiler/js-graph.h"
      8 #include "src/compiler/node-matchers.h"
      9 #include "src/objects-inl.h"
     10 #include "src/type-feedback-vector-inl.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 namespace compiler {
     15 
     16 namespace {
     17 
     18 VectorSlotPair CallCountFeedback(VectorSlotPair p) {
     19   // Extract call count from {p}.
     20   if (!p.IsValid()) return VectorSlotPair();
     21   CallICNexus n(p.vector(), p.slot());
     22   int const call_count = n.ExtractCallCount();
     23   if (call_count <= 0) return VectorSlotPair();
     24 
     25   // Create megamorphic CallIC feedback with the given {call_count}.
     26   StaticFeedbackVectorSpec spec;
     27   FeedbackVectorSlot slot = spec.AddCallICSlot();
     28   Handle<TypeFeedbackMetadata> metadata =
     29       TypeFeedbackMetadata::New(n.GetIsolate(), &spec);
     30   Handle<TypeFeedbackVector> vector =
     31       TypeFeedbackVector::New(n.GetIsolate(), metadata);
     32   CallICNexus nexus(vector, slot);
     33   nexus.ConfigureMegamorphic(call_count);
     34   return VectorSlotPair(vector, slot);
     35 }
     36 
     37 }  // namespace
     38 
     39 
     40 Reduction JSCallReducer::Reduce(Node* node) {
     41   switch (node->opcode()) {
     42     case IrOpcode::kJSCallConstruct:
     43       return ReduceJSCallConstruct(node);
     44     case IrOpcode::kJSCallFunction:
     45       return ReduceJSCallFunction(node);
     46     default:
     47       break;
     48   }
     49   return NoChange();
     50 }
     51 
     52 
     53 // ES6 section 22.1.1 The Array Constructor
     54 Reduction JSCallReducer::ReduceArrayConstructor(Node* node) {
     55   DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
     56   Node* target = NodeProperties::GetValueInput(node, 0);
     57   CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
     58 
     59   // Check if we have an allocation site from the CallIC.
     60   Handle<AllocationSite> site;
     61   if (p.feedback().IsValid()) {
     62     CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
     63     Handle<Object> feedback(nexus.GetFeedback(), isolate());
     64     if (feedback->IsAllocationSite()) {
     65       site = Handle<AllocationSite>::cast(feedback);
     66     }
     67   }
     68 
     69   // Turn the {node} into a {JSCreateArray} call.
     70   DCHECK_LE(2u, p.arity());
     71   size_t const arity = p.arity() - 2;
     72   NodeProperties::ReplaceValueInput(node, target, 0);
     73   NodeProperties::ReplaceValueInput(node, target, 1);
     74   // TODO(bmeurer): We might need to propagate the tail call mode to
     75   // the JSCreateArray operator, because an Array call in tail call
     76   // position must always properly consume the parent stack frame.
     77   NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
     78   return Changed(node);
     79 }
     80 
     81 
     82 // ES6 section 20.1.1 The Number Constructor
     83 Reduction JSCallReducer::ReduceNumberConstructor(Node* node) {
     84   DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
     85   CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
     86 
     87   // Turn the {node} into a {JSToNumber} call.
     88   DCHECK_LE(2u, p.arity());
     89   Node* value = (p.arity() == 2) ? jsgraph()->ZeroConstant()
     90                                  : NodeProperties::GetValueInput(node, 2);
     91   NodeProperties::ReplaceValueInputs(node, value);
     92   NodeProperties::ChangeOp(node, javascript()->ToNumber());
     93   return Changed(node);
     94 }
     95 
     96 
     97 // ES6 section 19.2.3.1 Function.prototype.apply ( thisArg, argArray )
     98 Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
     99   DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
    100   Node* target = NodeProperties::GetValueInput(node, 0);
    101   CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
    102   Handle<JSFunction> apply =
    103       Handle<JSFunction>::cast(HeapObjectMatcher(target).Value());
    104   size_t arity = p.arity();
    105   DCHECK_LE(2u, arity);
    106   ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny;
    107   if (arity == 2) {
    108     // Neither thisArg nor argArray was provided.
    109     convert_mode = ConvertReceiverMode::kNullOrUndefined;
    110     node->ReplaceInput(0, node->InputAt(1));
    111     node->ReplaceInput(1, jsgraph()->UndefinedConstant());
    112   } else if (arity == 3) {
    113     // The argArray was not provided, just remove the {target}.
    114     node->RemoveInput(0);
    115     --arity;
    116   } else if (arity == 4) {
    117     // Check if argArray is an arguments object, and {node} is the only value
    118     // user of argArray (except for value uses in frame states).
    119     Node* arg_array = NodeProperties::GetValueInput(node, 3);
    120     if (arg_array->opcode() != IrOpcode::kJSCreateArguments) return NoChange();
    121     for (Edge edge : arg_array->use_edges()) {
    122       if (edge.from()->opcode() == IrOpcode::kStateValues) continue;
    123       if (!NodeProperties::IsValueEdge(edge)) continue;
    124       if (edge.from() == node) continue;
    125       return NoChange();
    126     }
    127     // Get to the actual frame state from which to extract the arguments;
    128     // we can only optimize this in case the {node} was already inlined into
    129     // some other function (and same for the {arg_array}).
    130     CreateArgumentsType type = CreateArgumentsTypeOf(arg_array->op());
    131     Node* frame_state = NodeProperties::GetFrameStateInput(arg_array, 0);
    132     Node* outer_state = frame_state->InputAt(kFrameStateOuterStateInput);
    133     if (outer_state->opcode() != IrOpcode::kFrameState) return NoChange();
    134     FrameStateInfo outer_info = OpParameter<FrameStateInfo>(outer_state);
    135     if (outer_info.type() == FrameStateType::kArgumentsAdaptor) {
    136       // Need to take the parameters from the arguments adaptor.
    137       frame_state = outer_state;
    138     }
    139     FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
    140     int start_index = 0;
    141     if (type == CreateArgumentsType::kMappedArguments) {
    142       // Mapped arguments (sloppy mode) cannot be handled if they are aliased.
    143       Handle<SharedFunctionInfo> shared;
    144       if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
    145       if (shared->internal_formal_parameter_count() != 0) return NoChange();
    146     } else if (type == CreateArgumentsType::kRestParameter) {
    147       Handle<SharedFunctionInfo> shared;
    148       if (!state_info.shared_info().ToHandle(&shared)) return NoChange();
    149       start_index = shared->internal_formal_parameter_count();
    150     }
    151     // Remove the argArray input from the {node}.
    152     node->RemoveInput(static_cast<int>(--arity));
    153     // Add the actual parameters to the {node}, skipping the receiver.
    154     Node* const parameters = frame_state->InputAt(kFrameStateParametersInput);
    155     for (int i = start_index + 1; i < state_info.parameter_count(); ++i) {
    156       node->InsertInput(graph()->zone(), static_cast<int>(arity),
    157                         parameters->InputAt(i));
    158       ++arity;
    159     }
    160     // Drop the {target} from the {node}.
    161     node->RemoveInput(0);
    162     --arity;
    163   } else {
    164     return NoChange();
    165   }
    166   // Change {node} to the new {JSCallFunction} operator.
    167   NodeProperties::ChangeOp(
    168       node, javascript()->CallFunction(arity, CallCountFeedback(p.feedback()),
    169                                        convert_mode, p.tail_call_mode()));
    170   // Change context of {node} to the Function.prototype.apply context,
    171   // to ensure any exception is thrown in the correct context.
    172   NodeProperties::ReplaceContextInput(
    173       node, jsgraph()->HeapConstant(handle(apply->context(), isolate())));
    174   // Try to further reduce the JSCallFunction {node}.
    175   Reduction const reduction = ReduceJSCallFunction(node);
    176   return reduction.Changed() ? reduction : Changed(node);
    177 }
    178 
    179 
    180 // ES6 section 19.2.3.3 Function.prototype.call (thisArg, ...args)
    181 Reduction JSCallReducer::ReduceFunctionPrototypeCall(Node* node) {
    182   DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
    183   CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
    184   Handle<JSFunction> call = Handle<JSFunction>::cast(
    185       HeapObjectMatcher(NodeProperties::GetValueInput(node, 0)).Value());
    186   // Change context of {node} to the Function.prototype.call context,
    187   // to ensure any exception is thrown in the correct context.
    188   NodeProperties::ReplaceContextInput(
    189       node, jsgraph()->HeapConstant(handle(call->context(), isolate())));
    190   // Remove the target from {node} and use the receiver as target instead, and
    191   // the thisArg becomes the new target.  If thisArg was not provided, insert
    192   // undefined instead.
    193   size_t arity = p.arity();
    194   DCHECK_LE(2u, arity);
    195   ConvertReceiverMode convert_mode;
    196   if (arity == 2) {
    197     // The thisArg was not provided, use undefined as receiver.
    198     convert_mode = ConvertReceiverMode::kNullOrUndefined;
    199     node->ReplaceInput(0, node->InputAt(1));
    200     node->ReplaceInput(1, jsgraph()->UndefinedConstant());
    201   } else {
    202     // Just remove the target, which is the first value input.
    203     convert_mode = ConvertReceiverMode::kAny;
    204     node->RemoveInput(0);
    205     --arity;
    206   }
    207   NodeProperties::ChangeOp(
    208       node, javascript()->CallFunction(arity, CallCountFeedback(p.feedback()),
    209                                        convert_mode, p.tail_call_mode()));
    210   // Try to further reduce the JSCallFunction {node}.
    211   Reduction const reduction = ReduceJSCallFunction(node);
    212   return reduction.Changed() ? reduction : Changed(node);
    213 }
    214 
    215 
    216 Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
    217   DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
    218   CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
    219   Node* target = NodeProperties::GetValueInput(node, 0);
    220   Node* context = NodeProperties::GetContextInput(node);
    221   Node* control = NodeProperties::GetControlInput(node);
    222   Node* effect = NodeProperties::GetEffectInput(node);
    223   Node* frame_state = NodeProperties::FindFrameStateBefore(node);
    224 
    225   // Try to specialize JSCallFunction {node}s with constant {target}s.
    226   HeapObjectMatcher m(target);
    227   if (m.HasValue()) {
    228     if (m.Value()->IsJSFunction()) {
    229       Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
    230       Handle<SharedFunctionInfo> shared(function->shared(), isolate());
    231 
    232       // Raise a TypeError if the {target} is a "classConstructor".
    233       if (IsClassConstructor(shared->kind())) {
    234         NodeProperties::ReplaceValueInputs(node, target);
    235         NodeProperties::ChangeOp(
    236             node, javascript()->CallRuntime(
    237                       Runtime::kThrowConstructorNonCallableError, 1));
    238         return Changed(node);
    239       }
    240 
    241       // Check for known builtin functions.
    242       if (shared->HasBuiltinFunctionId()) {
    243         switch (shared->builtin_function_id()) {
    244           case kFunctionApply:
    245             return ReduceFunctionPrototypeApply(node);
    246           case kFunctionCall:
    247             return ReduceFunctionPrototypeCall(node);
    248           default:
    249             break;
    250         }
    251       }
    252 
    253       // Check for the Array constructor.
    254       if (*function == function->native_context()->array_function()) {
    255         return ReduceArrayConstructor(node);
    256       }
    257 
    258       // Check for the Number constructor.
    259       if (*function == function->native_context()->number_function()) {
    260         return ReduceNumberConstructor(node);
    261       }
    262     } else if (m.Value()->IsJSBoundFunction()) {
    263       Handle<JSBoundFunction> function =
    264           Handle<JSBoundFunction>::cast(m.Value());
    265       Handle<JSReceiver> bound_target_function(
    266           function->bound_target_function(), isolate());
    267       Handle<Object> bound_this(function->bound_this(), isolate());
    268       Handle<FixedArray> bound_arguments(function->bound_arguments(),
    269                                          isolate());
    270       CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
    271       ConvertReceiverMode const convert_mode =
    272           (bound_this->IsNull(isolate()) || bound_this->IsUndefined(isolate()))
    273               ? ConvertReceiverMode::kNullOrUndefined
    274               : ConvertReceiverMode::kNotNullOrUndefined;
    275       size_t arity = p.arity();
    276       DCHECK_LE(2u, arity);
    277       // Patch {node} to use [[BoundTargetFunction]] and [[BoundThis]].
    278       NodeProperties::ReplaceValueInput(
    279           node, jsgraph()->Constant(bound_target_function), 0);
    280       NodeProperties::ReplaceValueInput(node, jsgraph()->Constant(bound_this),
    281                                         1);
    282       // Insert the [[BoundArguments]] for {node}.
    283       for (int i = 0; i < bound_arguments->length(); ++i) {
    284         node->InsertInput(
    285             graph()->zone(), i + 2,
    286             jsgraph()->Constant(handle(bound_arguments->get(i), isolate())));
    287         arity++;
    288       }
    289       NodeProperties::ChangeOp(node, javascript()->CallFunction(
    290                                          arity, CallCountFeedback(p.feedback()),
    291                                          convert_mode, p.tail_call_mode()));
    292       // Try to further reduce the JSCallFunction {node}.
    293       Reduction const reduction = ReduceJSCallFunction(node);
    294       return reduction.Changed() ? reduction : Changed(node);
    295     }
    296 
    297     // Don't mess with other {node}s that have a constant {target}.
    298     // TODO(bmeurer): Also support proxies here.
    299     return NoChange();
    300   }
    301 
    302   // Not much we can do if deoptimization support is disabled.
    303   if (!(flags() & kDeoptimizationEnabled)) return NoChange();
    304 
    305   // Extract feedback from the {node} using the CallICNexus.
    306   if (!p.feedback().IsValid()) return NoChange();
    307   CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
    308   Handle<Object> feedback(nexus.GetFeedback(), isolate());
    309   if (feedback->IsAllocationSite()) {
    310     // Retrieve the Array function from the {node}.
    311     Node* array_function;
    312     Handle<Context> native_context;
    313     if (GetNativeContext(node).ToHandle(&native_context)) {
    314       array_function = jsgraph()->HeapConstant(
    315           handle(native_context->array_function(), isolate()));
    316     } else {
    317       Node* native_context = effect = graph()->NewNode(
    318           javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
    319           context, context, effect);
    320       array_function = effect = graph()->NewNode(
    321           javascript()->LoadContext(0, Context::ARRAY_FUNCTION_INDEX, true),
    322           native_context, native_context, effect);
    323     }
    324 
    325     // Check that the {target} is still the {array_function}.
    326     Node* check = graph()->NewNode(
    327         javascript()->StrictEqual(CompareOperationHints::Any()), target,
    328         array_function, context);
    329     control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
    330                                         frame_state, effect, control);
    331 
    332     // Turn the {node} into a {JSCreateArray} call.
    333     NodeProperties::ReplaceValueInput(node, array_function, 0);
    334     NodeProperties::ReplaceEffectInput(node, effect);
    335     NodeProperties::ReplaceControlInput(node, control);
    336     return ReduceArrayConstructor(node);
    337   } else if (feedback->IsWeakCell()) {
    338     Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
    339     if (cell->value()->IsJSFunction()) {
    340       Node* target_function =
    341           jsgraph()->Constant(handle(cell->value(), isolate()));
    342 
    343       // Check that the {target} is still the {target_function}.
    344       Node* check = graph()->NewNode(
    345           javascript()->StrictEqual(CompareOperationHints::Any()), target,
    346           target_function, context);
    347       control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
    348                                           frame_state, effect, control);
    349 
    350       // Specialize the JSCallFunction node to the {target_function}.
    351       NodeProperties::ReplaceValueInput(node, target_function, 0);
    352       NodeProperties::ReplaceEffectInput(node, effect);
    353       NodeProperties::ReplaceControlInput(node, control);
    354 
    355       // Try to further reduce the JSCallFunction {node}.
    356       Reduction const reduction = ReduceJSCallFunction(node);
    357       return reduction.Changed() ? reduction : Changed(node);
    358     }
    359   }
    360   return NoChange();
    361 }
    362 
    363 
    364 Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
    365   DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
    366   CallConstructParameters const& p = CallConstructParametersOf(node->op());
    367   DCHECK_LE(2u, p.arity());
    368   int const arity = static_cast<int>(p.arity() - 2);
    369   Node* target = NodeProperties::GetValueInput(node, 0);
    370   Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
    371   Node* context = NodeProperties::GetContextInput(node);
    372   Node* effect = NodeProperties::GetEffectInput(node);
    373   Node* control = NodeProperties::GetControlInput(node);
    374   Node* frame_state = NodeProperties::FindFrameStateBefore(node);
    375 
    376   // Try to specialize JSCallConstruct {node}s with constant {target}s.
    377   HeapObjectMatcher m(target);
    378   if (m.HasValue()) {
    379     if (m.Value()->IsJSFunction()) {
    380       Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
    381 
    382       // Raise a TypeError if the {target} is not a constructor.
    383       if (!function->IsConstructor()) {
    384         NodeProperties::ReplaceValueInputs(node, target);
    385         NodeProperties::ChangeOp(
    386             node, javascript()->CallRuntime(Runtime::kThrowCalledNonCallable));
    387         return Changed(node);
    388       }
    389 
    390       // Check for the ArrayConstructor.
    391       if (*function == function->native_context()->array_function()) {
    392         // Check if we have an allocation site.
    393         Handle<AllocationSite> site;
    394         if (p.feedback().IsValid()) {
    395           Handle<Object> feedback(
    396               p.feedback().vector()->Get(p.feedback().slot()), isolate());
    397           if (feedback->IsAllocationSite()) {
    398             site = Handle<AllocationSite>::cast(feedback);
    399           }
    400         }
    401 
    402         // Turn the {node} into a {JSCreateArray} call.
    403         for (int i = arity; i > 0; --i) {
    404           NodeProperties::ReplaceValueInput(
    405               node, NodeProperties::GetValueInput(node, i), i + 1);
    406         }
    407         NodeProperties::ReplaceValueInput(node, new_target, 1);
    408         NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
    409         return Changed(node);
    410       }
    411     }
    412 
    413     // Don't mess with other {node}s that have a constant {target}.
    414     // TODO(bmeurer): Also support optimizing bound functions and proxies here.
    415     return NoChange();
    416   }
    417 
    418   // Not much we can do if deoptimization support is disabled.
    419   if (!(flags() & kDeoptimizationEnabled)) return NoChange();
    420 
    421   // TODO(mvstanton): Use ConstructICNexus here, once available.
    422   Handle<Object> feedback;
    423   if (!p.feedback().IsValid()) return NoChange();
    424   feedback = handle(p.feedback().vector()->Get(p.feedback().slot()), isolate());
    425   if (feedback->IsAllocationSite()) {
    426     // The feedback is an AllocationSite, which means we have called the
    427     // Array function and collected transition (and pretenuring) feedback
    428     // for the resulting arrays.  This has to be kept in sync with the
    429     // implementation of the CallConstructStub.
    430     Handle<AllocationSite> site = Handle<AllocationSite>::cast(feedback);
    431 
    432     // Retrieve the Array function from the {node}.
    433     Node* array_function;
    434     Handle<Context> native_context;
    435     if (GetNativeContext(node).ToHandle(&native_context)) {
    436       array_function = jsgraph()->HeapConstant(
    437           handle(native_context->array_function(), isolate()));
    438     } else {
    439       Node* native_context = effect = graph()->NewNode(
    440           javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true),
    441           context, context, effect);
    442       array_function = effect = graph()->NewNode(
    443           javascript()->LoadContext(0, Context::ARRAY_FUNCTION_INDEX, true),
    444           native_context, native_context, effect);
    445     }
    446 
    447     // Check that the {target} is still the {array_function}.
    448     Node* check = graph()->NewNode(
    449         javascript()->StrictEqual(CompareOperationHints::Any()), target,
    450         array_function, context);
    451     control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
    452                                         frame_state, effect, control);
    453 
    454     // Turn the {node} into a {JSCreateArray} call.
    455     NodeProperties::ReplaceEffectInput(node, effect);
    456     NodeProperties::ReplaceControlInput(node, control);
    457     for (int i = arity; i > 0; --i) {
    458       NodeProperties::ReplaceValueInput(
    459           node, NodeProperties::GetValueInput(node, i), i + 1);
    460     }
    461     NodeProperties::ReplaceValueInput(node, new_target, 1);
    462     NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
    463     return Changed(node);
    464   } else if (feedback->IsWeakCell()) {
    465     Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
    466     if (cell->value()->IsJSFunction()) {
    467       Node* target_function =
    468           jsgraph()->Constant(handle(cell->value(), isolate()));
    469 
    470       // Check that the {target} is still the {target_function}.
    471       Node* check = graph()->NewNode(
    472           javascript()->StrictEqual(CompareOperationHints::Any()), target,
    473           target_function, context);
    474       control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check,
    475                                           frame_state, effect, control);
    476 
    477       // Specialize the JSCallConstruct node to the {target_function}.
    478       NodeProperties::ReplaceValueInput(node, target_function, 0);
    479       NodeProperties::ReplaceEffectInput(node, effect);
    480       NodeProperties::ReplaceControlInput(node, control);
    481       if (target == new_target) {
    482         NodeProperties::ReplaceValueInput(node, target_function, arity + 1);
    483       }
    484 
    485       // Try to further reduce the JSCallConstruct {node}.
    486       Reduction const reduction = ReduceJSCallConstruct(node);
    487       return reduction.Changed() ? reduction : Changed(node);
    488     }
    489   }
    490 
    491   return NoChange();
    492 }
    493 
    494 
    495 MaybeHandle<Context> JSCallReducer::GetNativeContext(Node* node) {
    496   Node* const context = NodeProperties::GetContextInput(node);
    497   return NodeProperties::GetSpecializationNativeContext(context,
    498                                                         native_context());
    499 }
    500 
    501 
    502 Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
    503 
    504 
    505 Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
    506 
    507 
    508 CommonOperatorBuilder* JSCallReducer::common() const {
    509   return jsgraph()->common();
    510 }
    511 
    512 
    513 JSOperatorBuilder* JSCallReducer::javascript() const {
    514   return jsgraph()->javascript();
    515 }
    516 
    517 }  // namespace compiler
    518 }  // namespace internal
    519 }  // namespace v8
    520