1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29#include "accessors.h"
30
31#include "contexts.h"
32#include "deoptimizer.h"
33#include "execution.h"
34#include "factory.h"
35#include "frames-inl.h"
36#include "isolate.h"
37#include "list-inl.h"
38#include "property-details.h"
39
40namespace v8 {
41namespace internal {
42
43
44template <class C>
45static C* FindInPrototypeChain(Object* obj, bool* found_it) {
46  ASSERT(!*found_it);
47  Heap* heap = HEAP;
48  while (!Is<C>(obj)) {
49    if (obj == heap->null_value()) return NULL;
50    obj = obj->GetPrototype();
51  }
52  *found_it = true;
53  return C::cast(obj);
54}
55
56
57// Entry point that never should be called.
58MaybeObject* Accessors::IllegalSetter(JSObject*, Object*, void*) {
59  UNREACHABLE();
60  return NULL;
61}
62
63
64Object* Accessors::IllegalGetAccessor(Object* object, void*) {
65  UNREACHABLE();
66  return object;
67}
68
69
70MaybeObject* Accessors::ReadOnlySetAccessor(JSObject*, Object* value, void*) {
71  // According to ECMA-262, section 8.6.2.2, page 28, setting
72  // read-only properties must be silently ignored.
73  return value;
74}
75
76
77//
78// Accessors::ArrayLength
79//
80
81
82MaybeObject* Accessors::ArrayGetLength(Object* object, void*) {
83  // Traverse the prototype chain until we reach an array.
84  bool found_it = false;
85  JSArray* holder = FindInPrototypeChain<JSArray>(object, &found_it);
86  if (!found_it) return Smi::FromInt(0);
87  return holder->length();
88}
89
90
91// The helper function will 'flatten' Number objects.
92Object* Accessors::FlattenNumber(Object* value) {
93  if (value->IsNumber() || !value->IsJSValue()) return value;
94  JSValue* wrapper = JSValue::cast(value);
95  ASSERT(Isolate::Current()->context()->global_context()->number_function()->
96      has_initial_map());
97  Map* number_map = Isolate::Current()->context()->global_context()->
98      number_function()->initial_map();
99  if (wrapper->map() == number_map) return wrapper->value();
100  return value;
101}
102
103
104MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) {
105  Isolate* isolate = object->GetIsolate();
106
107  // This means one of the object's prototypes is a JSArray and the
108  // object does not have a 'length' property.  Calling SetProperty
109  // causes an infinite loop.
110  if (!object->IsJSArray()) {
111    return object->SetLocalPropertyIgnoreAttributes(
112        isolate->heap()->length_symbol(), value, NONE);
113  }
114
115  value = FlattenNumber(value);
116
117  // Need to call methods that may trigger GC.
118  HandleScope scope(isolate);
119
120  // Protect raw pointers.
121  Handle<JSObject> object_handle(object, isolate);
122  Handle<Object> value_handle(value, isolate);
123
124  bool has_exception;
125  Handle<Object> uint32_v = Execution::ToUint32(value_handle, &has_exception);
126  if (has_exception) return Failure::Exception();
127  Handle<Object> number_v = Execution::ToNumber(value_handle, &has_exception);
128  if (has_exception) return Failure::Exception();
129
130  if (uint32_v->Number() == number_v->Number()) {
131    return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v);
132  }
133  return isolate->Throw(
134      *isolate->factory()->NewRangeError("invalid_array_length",
135                                         HandleVector<Object>(NULL, 0)));
136}
137
138
139const AccessorDescriptor Accessors::ArrayLength = {
140  ArrayGetLength,
141  ArraySetLength,
142  0
143};
144
145
146//
147// Accessors::StringLength
148//
149
150
151MaybeObject* Accessors::StringGetLength(Object* object, void*) {
152  Object* value = object;
153  if (object->IsJSValue()) value = JSValue::cast(object)->value();
154  if (value->IsString()) return Smi::FromInt(String::cast(value)->length());
155  // If object is not a string we return 0 to be compatible with WebKit.
156  // Note: Firefox returns the length of ToString(object).
157  return Smi::FromInt(0);
158}
159
160
161const AccessorDescriptor Accessors::StringLength = {
162  StringGetLength,
163  IllegalSetter,
164  0
165};
166
167
168//
169// Accessors::ScriptSource
170//
171
172
173MaybeObject* Accessors::ScriptGetSource(Object* object, void*) {
174  Object* script = JSValue::cast(object)->value();
175  return Script::cast(script)->source();
176}
177
178
179const AccessorDescriptor Accessors::ScriptSource = {
180  ScriptGetSource,
181  IllegalSetter,
182  0
183};
184
185
186//
187// Accessors::ScriptName
188//
189
190
191MaybeObject* Accessors::ScriptGetName(Object* object, void*) {
192  Object* script = JSValue::cast(object)->value();
193  return Script::cast(script)->name();
194}
195
196
197const AccessorDescriptor Accessors::ScriptName = {
198  ScriptGetName,
199  IllegalSetter,
200  0
201};
202
203
204//
205// Accessors::ScriptId
206//
207
208
209MaybeObject* Accessors::ScriptGetId(Object* object, void*) {
210  Object* script = JSValue::cast(object)->value();
211  return Script::cast(script)->id();
212}
213
214
215const AccessorDescriptor Accessors::ScriptId = {
216  ScriptGetId,
217  IllegalSetter,
218  0
219};
220
221
222//
223// Accessors::ScriptLineOffset
224//
225
226
227MaybeObject* Accessors::ScriptGetLineOffset(Object* object, void*) {
228  Object* script = JSValue::cast(object)->value();
229  return Script::cast(script)->line_offset();
230}
231
232
233const AccessorDescriptor Accessors::ScriptLineOffset = {
234  ScriptGetLineOffset,
235  IllegalSetter,
236  0
237};
238
239
240//
241// Accessors::ScriptColumnOffset
242//
243
244
245MaybeObject* Accessors::ScriptGetColumnOffset(Object* object, void*) {
246  Object* script = JSValue::cast(object)->value();
247  return Script::cast(script)->column_offset();
248}
249
250
251const AccessorDescriptor Accessors::ScriptColumnOffset = {
252  ScriptGetColumnOffset,
253  IllegalSetter,
254  0
255};
256
257
258//
259// Accessors::ScriptData
260//
261
262
263MaybeObject* Accessors::ScriptGetData(Object* object, void*) {
264  Object* script = JSValue::cast(object)->value();
265  return Script::cast(script)->data();
266}
267
268
269const AccessorDescriptor Accessors::ScriptData = {
270  ScriptGetData,
271  IllegalSetter,
272  0
273};
274
275
276//
277// Accessors::ScriptType
278//
279
280
281MaybeObject* Accessors::ScriptGetType(Object* object, void*) {
282  Object* script = JSValue::cast(object)->value();
283  return Script::cast(script)->type();
284}
285
286
287const AccessorDescriptor Accessors::ScriptType = {
288  ScriptGetType,
289  IllegalSetter,
290  0
291};
292
293
294//
295// Accessors::ScriptCompilationType
296//
297
298
299MaybeObject* Accessors::ScriptGetCompilationType(Object* object, void*) {
300  Object* script = JSValue::cast(object)->value();
301  return Script::cast(script)->compilation_type();
302}
303
304
305const AccessorDescriptor Accessors::ScriptCompilationType = {
306  ScriptGetCompilationType,
307  IllegalSetter,
308  0
309};
310
311
312//
313// Accessors::ScriptGetLineEnds
314//
315
316
317MaybeObject* Accessors::ScriptGetLineEnds(Object* object, void*) {
318  JSValue* wrapper = JSValue::cast(object);
319  Isolate* isolate = wrapper->GetIsolate();
320  HandleScope scope(isolate);
321  Handle<Script> script(Script::cast(wrapper->value()), isolate);
322  InitScriptLineEnds(script);
323  ASSERT(script->line_ends()->IsFixedArray());
324  Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
325  // We do not want anyone to modify this array from JS.
326  ASSERT(*line_ends == isolate->heap()->empty_fixed_array() ||
327         line_ends->map() == isolate->heap()->fixed_cow_array_map());
328  Handle<JSArray> js_array =
329      isolate->factory()->NewJSArrayWithElements(line_ends);
330  return *js_array;
331}
332
333
334const AccessorDescriptor Accessors::ScriptLineEnds = {
335  ScriptGetLineEnds,
336  IllegalSetter,
337  0
338};
339
340
341//
342// Accessors::ScriptGetContextData
343//
344
345
346MaybeObject* Accessors::ScriptGetContextData(Object* object, void*) {
347  Object* script = JSValue::cast(object)->value();
348  return Script::cast(script)->context_data();
349}
350
351
352const AccessorDescriptor Accessors::ScriptContextData = {
353  ScriptGetContextData,
354  IllegalSetter,
355  0
356};
357
358
359//
360// Accessors::ScriptGetEvalFromScript
361//
362
363
364MaybeObject* Accessors::ScriptGetEvalFromScript(Object* object, void*) {
365  Object* script = JSValue::cast(object)->value();
366  if (!Script::cast(script)->eval_from_shared()->IsUndefined()) {
367    Handle<SharedFunctionInfo> eval_from_shared(
368        SharedFunctionInfo::cast(Script::cast(script)->eval_from_shared()));
369
370    if (eval_from_shared->script()->IsScript()) {
371      Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
372      return *GetScriptWrapper(eval_from_script);
373    }
374  }
375  return HEAP->undefined_value();
376}
377
378
379const AccessorDescriptor Accessors::ScriptEvalFromScript = {
380  ScriptGetEvalFromScript,
381  IllegalSetter,
382  0
383};
384
385
386//
387// Accessors::ScriptGetEvalFromScriptPosition
388//
389
390
391MaybeObject* Accessors::ScriptGetEvalFromScriptPosition(Object* object, void*) {
392  HandleScope scope;
393  Handle<Script> script(Script::cast(JSValue::cast(object)->value()));
394
395  // If this is not a script compiled through eval there is no eval position.
396  int compilation_type = Smi::cast(script->compilation_type())->value();
397  if (compilation_type != Script::COMPILATION_TYPE_EVAL) {
398    return HEAP->undefined_value();
399  }
400
401  // Get the function from where eval was called and find the source position
402  // from the instruction offset.
403  Handle<Code> code(SharedFunctionInfo::cast(
404      script->eval_from_shared())->code());
405  return Smi::FromInt(code->SourcePosition(code->instruction_start() +
406                      script->eval_from_instructions_offset()->value()));
407}
408
409
410const AccessorDescriptor Accessors::ScriptEvalFromScriptPosition = {
411  ScriptGetEvalFromScriptPosition,
412  IllegalSetter,
413  0
414};
415
416
417//
418// Accessors::ScriptGetEvalFromFunctionName
419//
420
421
422MaybeObject* Accessors::ScriptGetEvalFromFunctionName(Object* object, void*) {
423  Object* script = JSValue::cast(object)->value();
424  Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(
425      Script::cast(script)->eval_from_shared()));
426
427
428  // Find the name of the function calling eval.
429  if (!shared->name()->IsUndefined()) {
430    return shared->name();
431  } else {
432    return shared->inferred_name();
433  }
434}
435
436
437const AccessorDescriptor Accessors::ScriptEvalFromFunctionName = {
438  ScriptGetEvalFromFunctionName,
439  IllegalSetter,
440  0
441};
442
443
444//
445// Accessors::FunctionPrototype
446//
447
448
449MaybeObject* Accessors::FunctionGetPrototype(Object* object, void*) {
450  Heap* heap = Isolate::Current()->heap();
451  bool found_it = false;
452  JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
453  if (!found_it) return heap->undefined_value();
454  while (!function->should_have_prototype()) {
455    found_it = false;
456    function = FindInPrototypeChain<JSFunction>(object->GetPrototype(),
457                                                &found_it);
458    // There has to be one because we hit the getter.
459    ASSERT(found_it);
460  }
461
462  if (!function->has_prototype()) {
463    Object* prototype;
464    { MaybeObject* maybe_prototype = heap->AllocateFunctionPrototype(function);
465      if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
466    }
467    Object* result;
468    { MaybeObject* maybe_result = function->SetPrototype(prototype);
469      if (!maybe_result->ToObject(&result)) return maybe_result;
470    }
471  }
472  return function->prototype();
473}
474
475
476MaybeObject* Accessors::FunctionSetPrototype(JSObject* object,
477                                             Object* value,
478                                             void*) {
479  Heap* heap = object->GetHeap();
480  bool found_it = false;
481  JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
482  if (!found_it) return heap->undefined_value();
483  if (!function->should_have_prototype()) {
484    // Since we hit this accessor, object will have no prototype property.
485    return object->SetLocalPropertyIgnoreAttributes(heap->prototype_symbol(),
486                                                    value,
487                                                    NONE);
488  }
489
490  Object* prototype;
491  { MaybeObject* maybe_prototype = function->SetPrototype(value);
492    if (!maybe_prototype->ToObject(&prototype)) return maybe_prototype;
493  }
494  ASSERT(function->prototype() == value);
495  return function;
496}
497
498
499const AccessorDescriptor Accessors::FunctionPrototype = {
500  FunctionGetPrototype,
501  FunctionSetPrototype,
502  0
503};
504
505
506//
507// Accessors::FunctionLength
508//
509
510
511MaybeObject* Accessors::FunctionGetLength(Object* object, void*) {
512  bool found_it = false;
513  JSFunction* function = FindInPrototypeChain<JSFunction>(object, &found_it);
514  if (!found_it) return Smi::FromInt(0);
515  // Check if already compiled.
516  if (!function->shared()->is_compiled()) {
517    // If the function isn't compiled yet, the length is not computed
518    // correctly yet. Compile it now and return the right length.
519    HandleScope scope;
520    Handle<JSFunction> handle(function);
521    if (!JSFunction::CompileLazy(handle, KEEP_EXCEPTION)) {
522      return Failure::Exception();
523    }
524    return Smi::FromInt(handle->shared()->length());
525  } else {
526    return Smi::FromInt(function->shared()->length());
527  }
528}
529
530
531const AccessorDescriptor Accessors::FunctionLength = {
532  FunctionGetLength,
533  ReadOnlySetAccessor,
534  0
535};
536
537
538//
539// Accessors::FunctionName
540//
541
542
543MaybeObject* Accessors::FunctionGetName(Object* object, void*) {
544  bool found_it = false;
545  JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
546  if (!found_it) return HEAP->undefined_value();
547  return holder->shared()->name();
548}
549
550
551const AccessorDescriptor Accessors::FunctionName = {
552  FunctionGetName,
553  ReadOnlySetAccessor,
554  0
555};
556
557
558//
559// Accessors::FunctionArguments
560//
561
562
563static MaybeObject* ConstructArgumentsObjectForInlinedFunction(
564    JavaScriptFrame* frame,
565    Handle<JSFunction> inlined_function,
566    int inlined_frame_index) {
567  Factory* factory = Isolate::Current()->factory();
568  Vector<SlotRef> args_slots =
569      SlotRef::ComputeSlotMappingForArguments(
570          frame,
571          inlined_frame_index,
572          inlined_function->shared()->formal_parameter_count());
573  int args_count = args_slots.length();
574  Handle<JSObject> arguments =
575      factory->NewArgumentsObject(inlined_function, args_count);
576  Handle<FixedArray> array = factory->NewFixedArray(args_count);
577  for (int i = 0; i < args_count; ++i) {
578    Handle<Object> value = args_slots[i].GetValue();
579    array->set(i, *value);
580  }
581  arguments->set_elements(*array);
582  args_slots.Dispose();
583
584  // Return the freshly allocated arguments object.
585  return *arguments;
586}
587
588
589MaybeObject* Accessors::FunctionGetArguments(Object* object, void*) {
590  Isolate* isolate = Isolate::Current();
591  HandleScope scope(isolate);
592  bool found_it = false;
593  JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
594  if (!found_it) return isolate->heap()->undefined_value();
595  Handle<JSFunction> function(holder, isolate);
596
597  if (function->shared()->native()) return isolate->heap()->null_value();
598  // Find the top invocation of the function by traversing frames.
599  List<JSFunction*> functions(2);
600  for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
601    JavaScriptFrame* frame = it.frame();
602    frame->GetFunctions(&functions);
603    for (int i = functions.length() - 1; i >= 0; i--) {
604      // Skip all frames that aren't invocations of the given function.
605      if (functions[i] != *function) continue;
606
607      if (i > 0) {
608        // The function in question was inlined.  Inlined functions have the
609        // correct number of arguments and no allocated arguments object, so
610        // we can construct a fresh one by interpreting the function's
611        // deoptimization input data.
612        return ConstructArgumentsObjectForInlinedFunction(frame, function, i);
613      }
614
615      if (!frame->is_optimized()) {
616        // If there is an arguments variable in the stack, we return that.
617        Handle<ScopeInfo> scope_info(function->shared()->scope_info());
618        int index = scope_info->StackSlotIndex(
619            isolate->heap()->arguments_symbol());
620        if (index >= 0) {
621          Handle<Object> arguments(frame->GetExpression(index), isolate);
622          if (!arguments->IsArgumentsMarker()) return *arguments;
623        }
624      }
625
626      // If there is no arguments variable in the stack or we have an
627      // optimized frame, we find the frame that holds the actual arguments
628      // passed to the function.
629      it.AdvanceToArgumentsFrame();
630      frame = it.frame();
631
632      // Get the number of arguments and construct an arguments object
633      // mirror for the right frame.
634      const int length = frame->ComputeParametersCount();
635      Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
636          function, length);
637      Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
638
639      // Copy the parameters to the arguments object.
640      ASSERT(array->length() == length);
641      for (int i = 0; i < length; i++) array->set(i, frame->GetParameter(i));
642      arguments->set_elements(*array);
643
644      // Return the freshly allocated arguments object.
645      return *arguments;
646    }
647    functions.Rewind(0);
648  }
649
650  // No frame corresponding to the given function found. Return null.
651  return isolate->heap()->null_value();
652}
653
654
655const AccessorDescriptor Accessors::FunctionArguments = {
656  FunctionGetArguments,
657  ReadOnlySetAccessor,
658  0
659};
660
661
662//
663// Accessors::FunctionCaller
664//
665
666
667static MaybeObject* CheckNonStrictCallerOrThrow(
668    Isolate* isolate,
669    JSFunction* caller) {
670  DisableAssertNoAllocation enable_allocation;
671  if (!caller->shared()->is_classic_mode()) {
672    return isolate->Throw(
673        *isolate->factory()->NewTypeError("strict_caller",
674                                          HandleVector<Object>(NULL, 0)));
675  }
676  return caller;
677}
678
679
680class FrameFunctionIterator {
681 public:
682  FrameFunctionIterator(Isolate* isolate, const AssertNoAllocation& promise)
683      : frame_iterator_(isolate),
684        functions_(2),
685        index_(0) {
686    GetFunctions();
687  }
688  JSFunction* next() {
689    if (functions_.length() == 0) return NULL;
690    JSFunction* next_function = functions_[index_];
691    index_--;
692    if (index_ < 0) {
693      GetFunctions();
694    }
695    return next_function;
696  }
697
698  // Iterate through functions until the first occurence of 'function'.
699  // Returns true if 'function' is found, and false if the iterator ends
700  // without finding it.
701  bool Find(JSFunction* function) {
702    JSFunction* next_function;
703    do {
704      next_function = next();
705      if (next_function == function) return true;
706    } while (next_function != NULL);
707    return false;
708  }
709
710 private:
711  void GetFunctions() {
712    functions_.Rewind(0);
713    if (frame_iterator_.done()) return;
714    JavaScriptFrame* frame = frame_iterator_.frame();
715    frame->GetFunctions(&functions_);
716    ASSERT(functions_.length() > 0);
717    frame_iterator_.Advance();
718    index_ = functions_.length() - 1;
719  }
720  JavaScriptFrameIterator frame_iterator_;
721  List<JSFunction*> functions_;
722  int index_;
723};
724
725
726MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
727  Isolate* isolate = Isolate::Current();
728  HandleScope scope(isolate);
729  AssertNoAllocation no_alloc;
730  bool found_it = false;
731  JSFunction* holder = FindInPrototypeChain<JSFunction>(object, &found_it);
732  if (!found_it) return isolate->heap()->undefined_value();
733  if (holder->shared()->native()) return isolate->heap()->null_value();
734  Handle<JSFunction> function(holder, isolate);
735
736  FrameFunctionIterator it(isolate, no_alloc);
737
738  // Find the function from the frames.
739  if (!it.Find(*function)) {
740    // No frame corresponding to the given function found. Return null.
741    return isolate->heap()->null_value();
742  }
743
744  // Find previously called non-toplevel function.
745  JSFunction* caller;
746  do {
747    caller = it.next();
748    if (caller == NULL) return isolate->heap()->null_value();
749  } while (caller->shared()->is_toplevel());
750
751  // If caller is a built-in function and caller's caller is also built-in,
752  // use that instead.
753  JSFunction* potential_caller = caller;
754  while (potential_caller != NULL && potential_caller->IsBuiltin()) {
755    caller = potential_caller;
756    potential_caller = it.next();
757  }
758  // If caller is bound, return null. This is compatible with JSC, and
759  // allows us to make bound functions use the strict function map
760  // and its associated throwing caller and arguments.
761  if (caller->shared()->bound()) {
762    return isolate->heap()->null_value();
763  }
764  return CheckNonStrictCallerOrThrow(isolate, caller);
765}
766
767
768const AccessorDescriptor Accessors::FunctionCaller = {
769  FunctionGetCaller,
770  ReadOnlySetAccessor,
771  0
772};
773
774
775//
776// Accessors::ObjectPrototype
777//
778
779
780MaybeObject* Accessors::ObjectGetPrototype(Object* receiver, void*) {
781  Object* current = receiver->GetPrototype();
782  while (current->IsJSObject() &&
783         JSObject::cast(current)->map()->is_hidden_prototype()) {
784    current = current->GetPrototype();
785  }
786  return current;
787}
788
789
790MaybeObject* Accessors::ObjectSetPrototype(JSObject* receiver,
791                                           Object* value,
792                                           void*) {
793  const bool skip_hidden_prototypes = true;
794  // To be consistent with other Set functions, return the value.
795  return receiver->SetPrototype(value, skip_hidden_prototypes);
796}
797
798
799const AccessorDescriptor Accessors::ObjectPrototype = {
800  ObjectGetPrototype,
801  ObjectSetPrototype,
802  0
803};
804
805} }  // namespace v8::internal
806