blob: ff099fc9e6db88e1597f37d80c1e0dccd0eb25ac [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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 <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000048#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000049#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000052#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000054#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000056#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000057#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
kasperl@chromium.org71affb52009-05-26 05:44:31 +000060namespace v8 {
61namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
63
ager@chromium.org3e875802009-06-29 08:26:34 +000064#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000065 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066
67// Cast the given object to a value of the specified type and store
68// it in a variable with the given name. If the object is not of the
69// expected type call IllegalOperation and return.
70#define CONVERT_CHECKED(Type, name, obj) \
71 RUNTIME_ASSERT(obj->Is##Type()); \
72 Type* name = Type::cast(obj);
73
74#define CONVERT_ARG_CHECKED(Type, name, index) \
75 RUNTIME_ASSERT(args[index]->Is##Type()); \
76 Handle<Type> name = args.at<Type>(index);
77
kasper.lundbd3ec4e2008-07-09 11:06:54 +000078// Cast the given object to a boolean and store it in a variable with
79// the given name. If the object is not a boolean call IllegalOperation
80// and return.
81#define CONVERT_BOOLEAN_CHECKED(name, obj) \
82 RUNTIME_ASSERT(obj->IsBoolean()); \
83 bool name = (obj)->IsTrue();
84
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000085// Cast the given argument to a Smi and store its value in an int variable
86// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000087// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088#define CONVERT_SMI_ARG_CHECKED(name, index) \
89 RUNTIME_ASSERT(args[index]->IsSmi()); \
90 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000091
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000092// Cast the given argument to a double and store it in a variable with
93// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000094// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
96 RUNTIME_ASSERT(args[index]->IsNumber()); \
97 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098
99// Call the specified converter on the object *comand store the result in
100// a variable of the specified type with the given name. If the
101// object is not a Number call IllegalOperation and return.
102#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
103 RUNTIME_ASSERT(obj->IsNumber()); \
104 type name = NumberTo##Type(obj);
105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000107MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
108 JSObject* boilerplate) {
109 StackLimitCheck check(isolate);
110 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000113 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000115 if (!maybe_result->ToObject(&result)) return maybe_result;
116 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000117 JSObject* copy = JSObject::cast(result);
118
119 // Deep copy local properties.
120 if (copy->HasFastProperties()) {
121 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000122 for (int i = 0; i < properties->length(); i++) {
123 Object* value = properties->get(i);
124 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000127 if (!maybe_result->ToObject(&result)) return maybe_result;
128 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000129 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 }
131 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000132 int nof = copy->map()->inobject_properties();
133 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 Object* value = copy->InObjectPropertyAt(i);
135 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000140 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000141 }
142 }
143 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 if (!maybe_result->ToObject(&result)) return maybe_result;
147 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 FixedArray* names = FixedArray::cast(result);
149 copy->GetLocalPropertyNames(names, 0);
150 for (int i = 0; i < names->length(); i++) {
151 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000155 // Only deep copy fields from the object literal expression.
156 // In particular, don't try to copy the length attribute of
157 // an array.
158 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 Object* value =
160 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000161 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000162 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
166 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000167 // Creating object copy for literals. No strict mode needed.
168 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 }
172 }
173 }
174
175 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000177 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000178 switch (copy->GetElementsKind()) {
179 case JSObject::FAST_ELEMENTS: {
180 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000181 if (elements->map() == heap->fixed_cow_array_map()) {
182 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000183#ifdef DEBUG
184 for (int i = 0; i < elements->length(); i++) {
185 ASSERT(!elements->get(i)->IsJSObject());
186 }
187#endif
188 } else {
189 for (int i = 0; i < elements->length(); i++) {
190 Object* value = elements->get(i);
191 if (value->IsJSObject()) {
192 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000193 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
194 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 if (!maybe_result->ToObject(&result)) return maybe_result;
196 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000197 elements->set(i, result);
198 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
200 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000202 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000203 case JSObject::DICTIONARY_ELEMENTS: {
204 NumberDictionary* element_dictionary = copy->element_dictionary();
205 int capacity = element_dictionary->Capacity();
206 for (int i = 0; i < capacity; i++) {
207 Object* k = element_dictionary->KeyAt(i);
208 if (element_dictionary->IsKey(k)) {
209 Object* value = element_dictionary->ValueAt(i);
210 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000211 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000212 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
213 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000214 if (!maybe_result->ToObject(&result)) return maybe_result;
215 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000216 element_dictionary->ValueAtPut(i, result);
217 }
218 }
219 }
220 break;
221 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000222 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
223 UNIMPLEMENTED();
224 break;
225 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
226 case JSObject::EXTERNAL_BYTE_ELEMENTS:
227 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
228 case JSObject::EXTERNAL_SHORT_ELEMENTS:
229 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
230 case JSObject::EXTERNAL_INT_ELEMENTS:
231 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
232 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
233 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
234 case JSObject::FAST_DOUBLE_ELEMENTS:
235 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000236 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000237 }
238 return copy;
239}
240
241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000242RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000243 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000245}
246
247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000248RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000249 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000250 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251}
252
253
ager@chromium.org236ad962008-09-25 09:45:57 +0000254static Handle<Map> ComputeObjectLiteralMap(
255 Handle<Context> context,
256 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000257 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000258 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 int properties_length = constant_properties->length();
260 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000262 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000264 for (int p = 0; p != properties_length; p += 2) {
265 Object* key = constant_properties->get(p);
266 uint32_t element_index = 0;
267 if (key->IsSymbol()) {
268 number_of_symbol_keys++;
269 } else if (key->ToArrayIndex(&element_index)) {
270 // An index key does not require space in the property backing store.
271 number_of_properties--;
272 } else {
273 // Bail out as a non-symbol non-index key makes caching impossible.
274 // ASSERT to make sure that the if condition after the loop is false.
275 ASSERT(number_of_symbol_keys != number_of_properties);
276 break;
277 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000279 // If we only have symbols and array indices among keys then we can
280 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000281 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000282 if ((number_of_symbol_keys == number_of_properties) &&
283 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000285 Handle<FixedArray> keys =
286 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000287 if (number_of_symbol_keys > 0) {
288 int index = 0;
289 for (int p = 0; p < properties_length; p += 2) {
290 Object* key = constant_properties->get(p);
291 if (key->IsSymbol()) {
292 keys->set(index++, key);
293 }
294 }
295 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000297 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000298 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 }
300 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000301 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000303 Handle<Map>(context->object_function()->initial_map()),
304 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000305}
306
307
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000308static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000309 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000310 Handle<FixedArray> literals,
311 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000312
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000313
314static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000316 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000317 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 bool should_have_fast_elements,
319 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000320 // Get the global context from the literals array. This is the
321 // context in which the function was created and we use the object
322 // function from this context to create the object literal. We do
323 // not use the object function from the current global context
324 // because this might be the object function from another context
325 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000326 Handle<Context> context =
327 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
328
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000329 // In case we have function literals, we want the object to be in
330 // slow properties mode for now. We don't go in the map cache because
331 // maps with constant functions can't be shared if the functions are
332 // not the same (which is the common case).
333 bool is_result_from_cache = false;
334 Handle<Map> map = has_function_literal
335 ? Handle<Map>(context->object_function()->initial_map())
336 : ComputeObjectLiteralMap(context,
337 constant_properties,
338 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000341
342 // Normalize the elements of the boilerplate to save space if needed.
343 if (!should_have_fast_elements) NormalizeElements(boilerplate);
344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 // Add the constant properties to the boilerplate.
346 int length = constant_properties->length();
347 bool should_transform =
348 !is_result_from_cache && boilerplate->HasFastProperties();
349 if (should_transform || has_function_literal) {
350 // Normalize the properties of object to avoid n^2 behavior
351 // when extending the object multiple properties. Indicate the number of
352 // properties to be added.
353 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
354 }
355
356 for (int index = 0; index < length; index +=2) {
357 Handle<Object> key(constant_properties->get(index+0), isolate);
358 Handle<Object> value(constant_properties->get(index+1), isolate);
359 if (value->IsFixedArray()) {
360 // The value contains the constant_properties of a
361 // simple object or array literal.
362 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
363 value = CreateLiteralBoilerplate(isolate, literals, array);
364 if (value.is_null()) return value;
365 }
366 Handle<Object> result;
367 uint32_t element_index = 0;
368 if (key->IsSymbol()) {
369 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
370 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000371 result = SetOwnElement(boilerplate,
372 element_index,
373 value,
374 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000375 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 Handle<String> name(String::cast(*key));
377 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000378 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
379 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000380 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000381 } else if (key->ToArrayIndex(&element_index)) {
382 // Array index (uint32).
383 result = SetOwnElement(boilerplate,
384 element_index,
385 value,
386 kNonStrictMode);
387 } else {
388 // Non-uint32 number.
389 ASSERT(key->IsNumber());
390 double num = key->Number();
391 char arr[100];
392 Vector<char> buffer(arr, ARRAY_SIZE(arr));
393 const char* str = DoubleToCString(num, buffer);
394 Handle<String> name =
395 isolate->factory()->NewStringFromAscii(CStrVector(str));
396 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
397 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000399 // If setting the property on the boilerplate throws an
400 // exception, the exception is converted to an empty handle in
401 // the handle based operations. In that case, we need to
402 // convert back to an exception.
403 if (result.is_null()) return result;
404 }
405
406 // Transform to fast properties if necessary. For object literals with
407 // containing function literals we defer this operation until after all
408 // computed properties have been assigned so that we can generate
409 // constant function properties.
410 if (should_transform && !has_function_literal) {
411 TransformToFastProperties(boilerplate,
412 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 }
414
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000415 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000416}
417
418
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000420 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421 Handle<FixedArray> literals,
422 Handle<FixedArray> elements) {
423 // Create the JSArray.
424 Handle<JSFunction> constructor(
425 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000426 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000428 const bool is_cow =
429 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000430 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432
433 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 if (is_cow) {
435#ifdef DEBUG
436 // Copy-on-write arrays must be shallow (and simple).
437 for (int i = 0; i < content->length(); i++) {
438 ASSERT(!content->get(i)->IsFixedArray());
439 }
440#endif
441 } else {
442 for (int i = 0; i < content->length(); i++) {
443 if (content->get(i)->IsFixedArray()) {
444 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000445 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000446 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
447 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000449 if (result.is_null()) return result;
450 content->set(i, *result);
451 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 }
453 }
454
455 // Set the elements.
456 Handle<JSArray>::cast(object)->SetContent(*content);
457 return object;
458}
459
460
461static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000463 Handle<FixedArray> literals,
464 Handle<FixedArray> array) {
465 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000468 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000469 return CreateObjectLiteralBoilerplate(isolate,
470 literals,
471 elements,
472 true,
473 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000474 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000475 return CreateObjectLiteralBoilerplate(isolate,
476 literals,
477 elements,
478 false,
479 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000480 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000482 default:
483 UNREACHABLE();
484 return Handle<Object>::null();
485 }
486}
487
488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000489RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000490 // Takes a FixedArray of elements containing the literal elements of
491 // the array literal and produces JSArray with those elements.
492 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000493 // which contains the context from which to get the Array function
494 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000495 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000496 ASSERT(args.length() == 3);
497 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000498 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000499 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000501 Handle<Object> object =
502 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000503 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *object);
507 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508}
509
510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000511RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000515 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000517 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
519 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000520
521 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000522 Handle<Object> boilerplate(literals->get(literals_index), isolate);
523 if (*boilerplate == isolate->heap()->undefined_value()) {
524 boilerplate = CreateObjectLiteralBoilerplate(isolate,
525 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000527 should_have_fast_elements,
528 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000529 if (boilerplate.is_null()) return Failure::Exception();
530 // Update the functions literal and return the boilerplate.
531 literals->set(literals_index, *boilerplate);
532 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000534}
535
536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000537RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000539 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000541 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000543 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
545 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000546
547 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000548 Handle<Object> boilerplate(literals->get(literals_index), isolate);
549 if (*boilerplate == isolate->heap()->undefined_value()) {
550 boilerplate = CreateObjectLiteralBoilerplate(isolate,
551 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000552 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000553 should_have_fast_elements,
554 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000555 if (boilerplate.is_null()) return Failure::Exception();
556 // Update the functions literal and return the boilerplate.
557 literals->set(literals_index, *boilerplate);
558 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000559 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560}
561
562
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000563RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565 ASSERT(args.length() == 3);
566 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000567 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000568 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
569
570 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 Handle<Object> boilerplate(literals->get(literals_index), isolate);
572 if (*boilerplate == isolate->heap()->undefined_value()) {
573 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574 if (boilerplate.is_null()) return Failure::Exception();
575 // Update the functions literal and return the boilerplate.
576 literals->set(literals_index, *boilerplate);
577 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579}
580
581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000582RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584 ASSERT(args.length() == 3);
585 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000586 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000587 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
588
589 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000590 Handle<Object> boilerplate(literals->get(literals_index), isolate);
591 if (*boilerplate == isolate->heap()->undefined_value()) {
592 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593 if (boilerplate.is_null()) return Failure::Exception();
594 // Update the functions literal and return the boilerplate.
595 literals->set(literals_index, *boilerplate);
596 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000597 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000599 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000600 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000601 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602}
603
604
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000605RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
606 ASSERT(args.length() == 2);
607 Object* handler = args[0];
608 Object* prototype = args[1];
609 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000610 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000611 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
612}
613
614
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000615RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
616 ASSERT(args.length() == 1);
617 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000618 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000619}
620
621
622RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
623 ASSERT(args.length() == 1);
624 CONVERT_CHECKED(JSProxy, proxy, args[0]);
625 return proxy->handler();
626}
627
628
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000629RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
630 ASSERT(args.length() == 1);
631 CONVERT_CHECKED(JSProxy, proxy, args[0]);
632 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000633 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000634}
635
636
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000637RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
638 HandleScope scope(isolate);
639 ASSERT(args.length() == 1);
640 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
641 ASSERT(weakmap->map()->inobject_properties() == 0);
642 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
643 weakmap->set_table(*table);
644 weakmap->set_next(Smi::FromInt(0));
645 return *weakmap;
646}
647
648
649RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
650 NoHandleAllocation ha;
651 ASSERT(args.length() == 2);
652 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
653 // TODO(mstarzinger): Currently we cannot use JSProxy objects as keys
654 // because they cannot be cast to JSObject to get an identity hash code.
655 CONVERT_ARG_CHECKED(JSObject, key, 1);
656 return weakmap->table()->Lookup(*key);
657}
658
659
660RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
661 HandleScope scope(isolate);
662 ASSERT(args.length() == 3);
663 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
664 // TODO(mstarzinger): See Runtime_WeakMapGet above.
665 CONVERT_ARG_CHECKED(JSObject, key, 1);
666 Handle<Object> value(args[2]);
667 Handle<ObjectHashTable> table(weakmap->table());
668 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
669 weakmap->set_table(*new_table);
670 return *value;
671}
672
673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675 NoHandleAllocation ha;
676 ASSERT(args.length() == 1);
677 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000678 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000679 return JSObject::cast(obj)->class_name();
680}
681
ager@chromium.org7c537e22008-10-16 08:43:32 +0000682
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000683RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
684 NoHandleAllocation ha;
685 ASSERT(args.length() == 1);
686 Object* obj = args[0];
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000687 do {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000688 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000689 } while (obj->IsJSObject() &&
690 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691 return obj;
692}
693
694
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000695RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 NoHandleAllocation ha;
697 ASSERT(args.length() == 2);
698 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
699 Object* O = args[0];
700 Object* V = args[1];
701 while (true) {
702 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000703 if (prototype->IsNull()) return isolate->heap()->false_value();
704 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000705 V = prototype;
706 }
707}
708
709
ager@chromium.org9085a012009-05-11 19:22:57 +0000710// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000711RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000712 NoHandleAllocation ha;
713 ASSERT(args.length() == 2);
714 CONVERT_CHECKED(JSObject, jsobject, args[0]);
715 CONVERT_CHECKED(JSObject, proto, args[1]);
716
717 // Sanity checks. The old prototype (that we are replacing) could
718 // theoretically be null, but if it is not null then check that we
719 // didn't already install a hidden prototype here.
720 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
721 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
722 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
723
724 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000725 Object* map_or_failure;
726 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
727 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
728 return maybe_map_or_failure;
729 }
730 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000731 Map* new_proto_map = Map::cast(map_or_failure);
732
lrn@chromium.org303ada72010-10-27 09:33:13 +0000733 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
734 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
735 return maybe_map_or_failure;
736 }
737 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000738 Map* new_map = Map::cast(map_or_failure);
739
740 // Set proto's prototype to be the old prototype of the object.
741 new_proto_map->set_prototype(jsobject->GetPrototype());
742 proto->set_map(new_proto_map);
743 new_proto_map->set_is_hidden_prototype();
744
745 // Set the object's prototype to proto.
746 new_map->set_prototype(proto);
747 jsobject->set_map(new_map);
748
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000749 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000750}
751
752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000753RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000755 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000756 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000757 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000758}
759
760
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000761// Recursively traverses hidden prototypes if property is not found
762static void GetOwnPropertyImplementation(JSObject* obj,
763 String* name,
764 LookupResult* result) {
765 obj->LocalLookupRealNamedProperty(name, result);
766
767 if (!result->IsProperty()) {
768 Object* proto = obj->GetPrototype();
769 if (proto->IsJSObject() &&
770 JSObject::cast(proto)->map()->is_hidden_prototype())
771 GetOwnPropertyImplementation(JSObject::cast(proto),
772 name, result);
773 }
774}
775
776
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000777static bool CheckAccessException(LookupResult* result,
778 v8::AccessType access_type) {
779 if (result->type() == CALLBACKS) {
780 Object* callback = result->GetCallbackObject();
781 if (callback->IsAccessorInfo()) {
782 AccessorInfo* info = AccessorInfo::cast(callback);
783 bool can_access =
784 (access_type == v8::ACCESS_HAS &&
785 (info->all_can_read() || info->all_can_write())) ||
786 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
787 (access_type == v8::ACCESS_SET && info->all_can_write());
788 return can_access;
789 }
790 }
791
792 return false;
793}
794
795
796static bool CheckAccess(JSObject* obj,
797 String* name,
798 LookupResult* result,
799 v8::AccessType access_type) {
800 ASSERT(result->IsProperty());
801
802 JSObject* holder = result->holder();
803 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000804 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000805 while (true) {
806 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000807 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000808 // Access check callback denied the access, but some properties
809 // can have a special permissions which override callbacks descision
810 // (currently see v8::AccessControl).
811 break;
812 }
813
814 if (current == holder) {
815 return true;
816 }
817
818 current = JSObject::cast(current->GetPrototype());
819 }
820
821 // API callbacks can have per callback access exceptions.
822 switch (result->type()) {
823 case CALLBACKS: {
824 if (CheckAccessException(result, access_type)) {
825 return true;
826 }
827 break;
828 }
829 case INTERCEPTOR: {
830 // If the object has an interceptor, try real named properties.
831 // Overwrite the result to fetch the correct property later.
832 holder->LookupRealNamedProperty(name, result);
833 if (result->IsProperty()) {
834 if (CheckAccessException(result, access_type)) {
835 return true;
836 }
837 }
838 break;
839 }
840 default:
841 break;
842 }
843
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000845 return false;
846}
847
848
849// TODO(1095): we should traverse hidden prototype hierachy as well.
850static bool CheckElementAccess(JSObject* obj,
851 uint32_t index,
852 v8::AccessType access_type) {
853 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000855 return false;
856 }
857
858 return true;
859}
860
861
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000862// Enumerator used as indices into the array returned from GetOwnProperty
863enum PropertyDescriptorIndices {
864 IS_ACCESSOR_INDEX,
865 VALUE_INDEX,
866 GETTER_INDEX,
867 SETTER_INDEX,
868 WRITABLE_INDEX,
869 ENUMERABLE_INDEX,
870 CONFIGURABLE_INDEX,
871 DESCRIPTOR_SIZE
872};
873
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000874// Returns an array with the property description:
875// if args[1] is not a property on args[0]
876// returns undefined
877// if args[1] is a data property on args[0]
878// [false, value, Writeable, Enumerable, Configurable]
879// if args[1] is an accessor on args[0]
880// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000881RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000882 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 Heap* heap = isolate->heap();
884 HandleScope scope(isolate);
885 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
886 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000887 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000888 CONVERT_ARG_CHECKED(JSObject, obj, 0);
889 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000890
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000891 // This could be an element.
892 uint32_t index;
893 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000894 switch (obj->HasLocalElement(index)) {
895 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000896 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000897
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000898 case JSObject::STRING_CHARACTER_ELEMENT: {
899 // Special handling of string objects according to ECMAScript 5
900 // 15.5.5.2. Note that this might be a string object with elements
901 // other than the actual string value. This is covered by the
902 // subsequent cases.
903 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
904 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000905 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000908 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 elms->set(WRITABLE_INDEX, heap->false_value());
910 elms->set(ENUMERABLE_INDEX, heap->false_value());
911 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000912 return *desc;
913 }
914
915 case JSObject::INTERCEPTED_ELEMENT:
916 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000917 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000918 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000920 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000921 elms->set(WRITABLE_INDEX, heap->true_value());
922 elms->set(ENUMERABLE_INDEX, heap->true_value());
923 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000924 return *desc;
925 }
926
927 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000928 Handle<JSObject> holder = obj;
929 if (obj->IsJSGlobalProxy()) {
930 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 ASSERT(proto->IsJSGlobalObject());
933 holder = Handle<JSObject>(JSObject::cast(proto));
934 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000935 FixedArray* elements = FixedArray::cast(holder->elements());
936 NumberDictionary* dictionary = NULL;
937 if (elements->map() == heap->non_strict_arguments_elements_map()) {
938 dictionary = NumberDictionary::cast(elements->get(1));
939 } else {
940 dictionary = NumberDictionary::cast(elements);
941 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000942 int entry = dictionary->FindEntry(index);
943 ASSERT(entry != NumberDictionary::kNotFound);
944 PropertyDetails details = dictionary->DetailsAt(entry);
945 switch (details.type()) {
946 case CALLBACKS: {
947 // This is an accessor property with getter and/or setter.
948 FixedArray* callbacks =
949 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000950 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000951 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
952 elms->set(GETTER_INDEX, callbacks->get(0));
953 }
954 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
955 elms->set(SETTER_INDEX, callbacks->get(1));
956 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000957 break;
958 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000959 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000960 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000961 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000962 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000963 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000964 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000966 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000967 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000968 default:
969 UNREACHABLE();
970 break;
971 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
973 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000974 return *desc;
975 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000976 }
977 }
978
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000979 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000980 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000981
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000982 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000984 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000985
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000986 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000987 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000988 }
989
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
991 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000992
993 bool is_js_accessor = (result.type() == CALLBACKS) &&
994 (result.GetCallbackObject()->IsFixedArray());
995
996 if (is_js_accessor) {
997 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000999
1000 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1001 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1002 elms->set(GETTER_INDEX, structure->get(0));
1003 }
1004 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1005 elms->set(SETTER_INDEX, structure->get(1));
1006 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001007 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001008 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1009 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001010
1011 PropertyAttributes attrs;
1012 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001013 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001014 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1015 if (!maybe_value->ToObject(&value)) return maybe_value;
1016 }
1017 elms->set(VALUE_INDEX, value);
1018 }
1019
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001020 return *desc;
1021}
1022
1023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001024RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001025 ASSERT(args.length() == 1);
1026 CONVERT_CHECKED(JSObject, obj, args[0]);
1027 return obj->PreventExtensions();
1028}
1029
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001031RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001032 ASSERT(args.length() == 1);
1033 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001034 if (obj->IsJSGlobalProxy()) {
1035 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001036 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001037 ASSERT(proto->IsJSGlobalObject());
1038 obj = JSObject::cast(proto);
1039 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001040 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001041}
1042
1043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001044RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001045 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001047 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1048 CONVERT_ARG_CHECKED(String, pattern, 1);
1049 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001050 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1051 if (result.is_null()) return Failure::Exception();
1052 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053}
1054
1055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001056RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001057 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001059 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001061}
1062
1063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001064RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065 ASSERT(args.length() == 1);
1066 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001067 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069}
1070
1071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001072RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 ASSERT(args.length() == 2);
1074 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001076 int index = field->value();
1077 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1078 InstanceType type = templ->map()->instance_type();
1079 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1080 type == OBJECT_TEMPLATE_INFO_TYPE);
1081 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001082 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001083 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1084 } else {
1085 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1086 }
1087 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088}
1089
1090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001091RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001092 ASSERT(args.length() == 1);
1093 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001094 Map* old_map = object->map();
1095 bool needs_access_checks = old_map->is_access_check_needed();
1096 if (needs_access_checks) {
1097 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001098 Object* new_map;
1099 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1100 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1101 }
ager@chromium.org32912102009-01-16 10:38:43 +00001102
1103 Map::cast(new_map)->set_is_access_check_needed(false);
1104 object->set_map(Map::cast(new_map));
1105 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001106 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001107}
1108
1109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001110RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001111 ASSERT(args.length() == 1);
1112 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001113 Map* old_map = object->map();
1114 if (!old_map->is_access_check_needed()) {
1115 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001116 Object* new_map;
1117 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1118 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1119 }
ager@chromium.org32912102009-01-16 10:38:43 +00001120
1121 Map::cast(new_map)->set_is_access_check_needed(true);
1122 object->set_map(Map::cast(new_map));
1123 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001124 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001125}
1126
1127
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001128static Failure* ThrowRedeclarationError(Isolate* isolate,
1129 const char* type,
1130 Handle<String> name) {
1131 HandleScope scope(isolate);
1132 Handle<Object> type_handle =
1133 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 Handle<Object> args[2] = { type_handle, name };
1135 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001136 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1137 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138}
1139
1140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001141RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001142 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001143 HandleScope scope(isolate);
1144 Handle<GlobalObject> global = Handle<GlobalObject>(
1145 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146
ager@chromium.org3811b432009-10-28 14:53:37 +00001147 Handle<Context> context = args.at<Context>(0);
1148 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001149 bool is_eval = args.smi_at(2) == 1;
1150 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001151 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001152
1153 // Compute the property attributes. According to ECMA-262, section
1154 // 13, page 71, the property must be read-only and
1155 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1156 // property as read-only, so we don't either.
1157 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1158
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001159 // Traverse the name/value pairs and set the properties.
1160 int length = pairs->length();
1161 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001162 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001164 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165
1166 // We have to declare a global const property. To capture we only
1167 // assign to it when evaluating the assignment for "const x =
1168 // <expr>" the initial value is the hole.
1169 bool is_const_property = value->IsTheHole();
1170
1171 if (value->IsUndefined() || is_const_property) {
1172 // Lookup the property in the global object, and don't set the
1173 // value of the variable if the property is already there.
1174 LookupResult lookup;
1175 global->Lookup(*name, &lookup);
1176 if (lookup.IsProperty()) {
1177 // Determine if the property is local by comparing the holder
1178 // against the global object. The information will be used to
1179 // avoid throwing re-declaration errors when declaring
1180 // variables or constants that exist in the prototype chain.
1181 bool is_local = (*global == lookup.holder());
1182 // Get the property attributes and determine if the property is
1183 // read-only.
1184 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1185 bool is_read_only = (attributes & READ_ONLY) != 0;
1186 if (lookup.type() == INTERCEPTOR) {
1187 // If the interceptor says the property is there, we
1188 // just return undefined without overwriting the property.
1189 // Otherwise, we continue to setting the property.
1190 if (attributes != ABSENT) {
1191 // Check if the existing property conflicts with regards to const.
1192 if (is_local && (is_read_only || is_const_property)) {
1193 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195 };
1196 // The property already exists without conflicting: Go to
1197 // the next declaration.
1198 continue;
1199 }
1200 // Fall-through and introduce the absent property by using
1201 // SetProperty.
1202 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001203 // For const properties, we treat a callback with this name
1204 // even in the prototype as a conflicting declaration.
1205 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001206 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001207 }
1208 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209 if (is_local && (is_read_only || is_const_property)) {
1210 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001211 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212 }
1213 // The property already exists without conflicting: Go to
1214 // the next declaration.
1215 continue;
1216 }
1217 }
1218 } else {
1219 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001220 Handle<SharedFunctionInfo> shared =
1221 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001223 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1224 context,
1225 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 value = function;
1227 }
1228
1229 LookupResult lookup;
1230 global->LocalLookup(*name, &lookup);
1231
1232 PropertyAttributes attributes = is_const_property
1233 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1234 : base;
1235
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001236 // There's a local property that we need to overwrite because
1237 // we're either declaring a function or there's an interceptor
1238 // that claims the property is absent.
1239 //
1240 // Check for conflicting re-declarations. We cannot have
1241 // conflicting types in case of intercepted properties because
1242 // they are absent.
1243 if (lookup.IsProperty() &&
1244 (lookup.type() != INTERCEPTOR) &&
1245 (lookup.IsReadOnly() || is_const_property)) {
1246 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001248 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001250 // Safari does not allow the invocation of callback setters for
1251 // function declarations. To mimic this behavior, we do not allow
1252 // the invocation of setters for function values. This makes a
1253 // difference for global functions with the same names as event
1254 // handlers such as "function onload() {}". Firefox does call the
1255 // onload setter in those case and Safari does not. We follow
1256 // Safari for compatibility.
1257 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001258 // Do not change DONT_DELETE to false from true.
1259 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1260 attributes = static_cast<PropertyAttributes>(
1261 attributes | (lookup.GetAttributes() & DONT_DELETE));
1262 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001263 RETURN_IF_EMPTY_HANDLE(isolate,
1264 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001265 name,
1266 value,
1267 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 RETURN_IF_EMPTY_HANDLE(isolate,
1270 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001271 name,
1272 value,
1273 attributes,
1274 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001275 }
1276 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001277
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001278 ASSERT(!isolate->has_pending_exception());
1279 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280}
1281
1282
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001283RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001284 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001285 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286
ager@chromium.org7c537e22008-10-16 08:43:32 +00001287 CONVERT_ARG_CHECKED(Context, context, 0);
1288 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001289 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001290 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001291 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001293 // Declarations are always done in a function or global context.
1294 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295
1296 int index;
1297 PropertyAttributes attributes;
1298 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001299 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 context->Lookup(name, flags, &index, &attributes);
1301
1302 if (attributes != ABSENT) {
1303 // The name was declared before; check for conflicting
1304 // re-declarations: This is similar to the code in parser.cc in
1305 // the AstBuildingParser::Declare function.
1306 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1307 // Functions are not read-only.
1308 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1309 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 }
1312
1313 // Initialize it if necessary.
1314 if (*initial_value != NULL) {
1315 if (index >= 0) {
1316 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001317 // the function context or the arguments object.
1318 if (holder->IsContext()) {
1319 ASSERT(holder.is_identical_to(context));
1320 if (((attributes & READ_ONLY) == 0) ||
1321 context->get(index)->IsTheHole()) {
1322 context->set(index, *initial_value);
1323 }
1324 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001325 // The holder is an arguments object.
1326 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001327 Handle<Object> result = SetElement(arguments, index, initial_value,
1328 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001329 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330 }
1331 } else {
1332 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001333 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001334 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001335 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001336 SetProperty(context_ext, name, initial_value,
1337 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 }
1339 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001342 // The property is not in the function context. It needs to be
1343 // "declared" in the function context's extension context, or in the
1344 // global context.
1345 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001346 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001347 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001348 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001349 } else {
1350 // The function context's extension context does not exists - allocate
1351 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001352 context_ext = isolate->factory()->NewJSObject(
1353 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001354 // And store it in the extension slot.
1355 context->set_extension(*context_ext);
1356 }
1357 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
ager@chromium.org7c537e22008-10-16 08:43:32 +00001359 // Declare the property by setting it to the initial value if provided,
1360 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1361 // constant declarations).
1362 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001363 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001364 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001365 // Declaring a const context slot is a conflicting declaration if
1366 // there is a callback with that name in a prototype. It is
1367 // allowed to introduce const variables in
1368 // JSContextExtensionObjects. They are treated specially in
1369 // SetProperty and no setters are invoked for those since they are
1370 // not real JSObjects.
1371 if (initial_value->IsTheHole() &&
1372 !context_ext->IsJSContextExtensionObject()) {
1373 LookupResult lookup;
1374 context_ext->Lookup(*name, &lookup);
1375 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001376 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001377 }
1378 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001379 RETURN_IF_EMPTY_HANDLE(isolate,
1380 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001381 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001382 }
1383
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001384 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385}
1386
1387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001388RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001390 // args[0] == name
1391 // args[1] == strict_mode
1392 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393
1394 // Determine if we need to assign to the variable if it already
1395 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001396 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1397 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
1399 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001400 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001401 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001402 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001403 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404
1405 // According to ECMA-262, section 12.2, page 62, the property must
1406 // not be deletable.
1407 PropertyAttributes attributes = DONT_DELETE;
1408
1409 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001410 // there, there is a property with this name in the prototype chain.
1411 // We follow Safari and Firefox behavior and only set the property
1412 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001413 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001414 // Note that objects can have hidden prototypes, so we need to traverse
1415 // the whole chain of hidden prototypes to do a 'local' lookup.
1416 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001418 while (true) {
1419 real_holder->LocalLookup(*name, &lookup);
1420 if (lookup.IsProperty()) {
1421 // Determine if this is a redeclaration of something read-only.
1422 if (lookup.IsReadOnly()) {
1423 // If we found readonly property on one of hidden prototypes,
1424 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 if (real_holder != isolate->context()->global()) break;
1426 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001427 }
1428
1429 // Determine if this is a redeclaration of an intercepted read-only
1430 // property and figure out if the property exists at all.
1431 bool found = true;
1432 PropertyType type = lookup.type();
1433 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001434 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001435 Handle<JSObject> holder(real_holder);
1436 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1437 real_holder = *holder;
1438 if (intercepted == ABSENT) {
1439 // The interceptor claims the property isn't there. We need to
1440 // make sure to introduce it.
1441 found = false;
1442 } else if ((intercepted & READ_ONLY) != 0) {
1443 // The property is present, but read-only. Since we're trying to
1444 // overwrite it with a variable declaration we must throw a
1445 // re-declaration error. However if we found readonly property
1446 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001447 if (real_holder != isolate->context()->global()) break;
1448 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001449 }
1450 }
1451
1452 if (found && !assign) {
1453 // The global property is there and we're not assigning any value
1454 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001455 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001456 }
1457
1458 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001459 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001460 return real_holder->SetProperty(
1461 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001462 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001463
1464 Object* proto = real_holder->GetPrototype();
1465 if (!proto->IsJSObject())
1466 break;
1467
1468 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1469 break;
1470
1471 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 }
1473
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001474 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001475 if (assign) {
1476 return global->SetProperty(*name, args[2], attributes, strict_mode);
1477 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001478 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479}
1480
1481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001482RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 // All constants are declared with an initial value. The name
1484 // of the constant is the first argument and the initial value
1485 // is the second.
1486 RUNTIME_ASSERT(args.length() == 2);
1487 CONVERT_ARG_CHECKED(String, name, 0);
1488 Handle<Object> value = args.at<Object>(1);
1489
1490 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001491 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001492
1493 // According to ECMA-262, section 12.2, page 62, the property must
1494 // not be deletable. Since it's a const, it must be READ_ONLY too.
1495 PropertyAttributes attributes =
1496 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1497
1498 // Lookup the property locally in the global object. If it isn't
1499 // there, we add the property and take special precautions to always
1500 // add it as a local property even in case of callbacks in the
1501 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001502 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001503 LookupResult lookup;
1504 global->LocalLookup(*name, &lookup);
1505 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001506 return global->SetLocalPropertyIgnoreAttributes(*name,
1507 *value,
1508 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509 }
1510
1511 // Determine if this is a redeclaration of something not
1512 // read-only. In case the result is hidden behind an interceptor we
1513 // need to ask it for the property attributes.
1514 if (!lookup.IsReadOnly()) {
1515 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001516 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517 }
1518
1519 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1520
1521 // Throw re-declaration error if the intercepted property is present
1522 // but not read-only.
1523 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001524 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001525 }
1526
1527 // Restore global object from context (in case of GC) and continue
1528 // with setting the value because the property is either absent or
1529 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001530 HandleScope handle_scope(isolate);
1531 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001532
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001533 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 // property through an interceptor and only do it if it's
1535 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001536 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001537 RETURN_IF_EMPTY_HANDLE(isolate,
1538 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001539 name,
1540 value,
1541 attributes,
1542 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 return *value;
1544 }
1545
1546 // Set the value, but only we're assigning the initial value to a
1547 // constant. For now, we determine this by checking if the
1548 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001549 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550 PropertyType type = lookup.type();
1551 if (type == FIELD) {
1552 FixedArray* properties = global->properties();
1553 int index = lookup.GetFieldIndex();
1554 if (properties->get(index)->IsTheHole()) {
1555 properties->set(index, *value);
1556 }
1557 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001558 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1559 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 }
1561 } else {
1562 // Ignore re-initialization of constants that have already been
1563 // assigned a function value.
1564 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1565 }
1566
1567 // Use the set value as the result of the operation.
1568 return *value;
1569}
1570
1571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001572RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001573 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 ASSERT(args.length() == 3);
1575
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001576 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577 ASSERT(!value->IsTheHole());
1578 CONVERT_ARG_CHECKED(Context, context, 1);
1579 Handle<String> name(String::cast(args[2]));
1580
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001581 // Initializations are always done in a function or global context.
1582 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583
1584 int index;
1585 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001586 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001587 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 context->Lookup(name, flags, &index, &attributes);
1589
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001590 // In most situations, the property introduced by the const
1591 // declaration should be present in the context extension object.
1592 // However, because declaration and initialization are separate, the
1593 // property might have been deleted (if it was introduced by eval)
1594 // before we reach the initialization point.
1595 //
1596 // Example:
1597 //
1598 // function f() { eval("delete x; const x;"); }
1599 //
1600 // In that case, the initialization behaves like a normal assignment
1601 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001603 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001604 // Property was found in a context. Perform the assignment if we
1605 // found some non-constant or an uninitialized constant.
1606 Handle<Context> context = Handle<Context>::cast(holder);
1607 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1608 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001609 }
1610 } else {
1611 // The holder is an arguments object.
1612 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001613 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001614 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001615 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001616 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 }
1618 return *value;
1619 }
1620
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001621 // The property could not be found, we introduce it in the global
1622 // context.
1623 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001624 Handle<JSObject> global = Handle<JSObject>(
1625 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001626 // Strict mode not needed (const disallowed in strict mode).
1627 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001628 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001629 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001630 return *value;
1631 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001633 // The property was present in a context extension object.
1634 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001636 if (*context_ext == context->extension()) {
1637 // This is the property that was introduced by the const
1638 // declaration. Set it if it hasn't been set before. NOTE: We
1639 // cannot use GetProperty() to get the current value as it
1640 // 'unholes' the value.
1641 LookupResult lookup;
1642 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1643 ASSERT(lookup.IsProperty()); // the property was declared
1644 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1645
1646 PropertyType type = lookup.type();
1647 if (type == FIELD) {
1648 FixedArray* properties = context_ext->properties();
1649 int index = lookup.GetFieldIndex();
1650 if (properties->get(index)->IsTheHole()) {
1651 properties->set(index, *value);
1652 }
1653 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001654 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1655 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001656 }
1657 } else {
1658 // We should not reach here. Any real, named property should be
1659 // either a field or a dictionary slot.
1660 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001661 }
1662 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001663 // The property was found in a different context extension object.
1664 // Set it if it is not a read-only property.
1665 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001666 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001667 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001668 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001669 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001670 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001671 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001672
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673 return *value;
1674}
1675
1676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001677RUNTIME_FUNCTION(MaybeObject*,
1678 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001679 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001680 ASSERT(args.length() == 2);
1681 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001682 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001683 if (object->HasFastProperties()) {
1684 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1685 }
1686 return *object;
1687}
1688
1689
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001690RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001691 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001692 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001693 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1694 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001695 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001696 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001697 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001698 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001699 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001700 RUNTIME_ASSERT(index >= 0);
1701 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001702 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001703 Handle<Object> result = RegExpImpl::Exec(regexp,
1704 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001705 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001706 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001707 if (result.is_null()) return Failure::Exception();
1708 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001709}
1710
1711
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001712RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001713 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001714 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001715 if (elements_count < 0 ||
1716 elements_count > FixedArray::kMaxLength ||
1717 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001718 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001719 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001720 Object* new_object;
1721 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001723 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1724 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001725 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1727 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001728 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1729 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001730 {
1731 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001732 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001733 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001734 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001735 }
1736 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001738 array->set_elements(elements);
1739 array->set_length(Smi::FromInt(elements_count));
1740 // Write in-object properties after the length of the array.
1741 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1742 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1743 return array;
1744}
1745
1746
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001747RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001748 AssertNoAllocation no_alloc;
1749 ASSERT(args.length() == 5);
1750 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1751 CONVERT_CHECKED(String, source, args[1]);
1752
1753 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001755
1756 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001757 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001758
1759 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001760 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001761
1762 Map* map = regexp->map();
1763 Object* constructor = map->constructor();
1764 if (constructor->IsJSFunction() &&
1765 JSFunction::cast(constructor)->initial_map() == map) {
1766 // If we still have the original map, set in-object properties directly.
1767 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1768 // TODO(lrn): Consider skipping write barrier on booleans as well.
1769 // Both true and false should be in oldspace at all times.
1770 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1771 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1772 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1773 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1774 Smi::FromInt(0),
1775 SKIP_WRITE_BARRIER);
1776 return regexp;
1777 }
1778
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001780 PropertyAttributes final =
1781 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1782 PropertyAttributes writable =
1783 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001784 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001785 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001786 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001787 source,
1788 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001789 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001791 global,
1792 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001793 ASSERT(!result->IsFailure());
1794 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001796 ignoreCase,
1797 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001798 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001799 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001800 multiline,
1801 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001802 ASSERT(!result->IsFailure());
1803 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001805 Smi::FromInt(0),
1806 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001807 ASSERT(!result->IsFailure());
1808 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001809 return regexp;
1810}
1811
1812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001813RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001815 ASSERT(args.length() == 1);
1816 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1817 // This is necessary to enable fast checks for absence of elements
1818 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001819 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001820 return Smi::FromInt(0);
1821}
1822
1823
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001824static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1825 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001826 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001827 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001828 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1829 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1830 Handle<JSFunction> optimized =
1831 isolate->factory()->NewFunction(key,
1832 JS_OBJECT_TYPE,
1833 JSObject::kHeaderSize,
1834 code,
1835 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001836 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001837 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001838 return optimized;
1839}
1840
1841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001842RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001843 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001844 ASSERT(args.length() == 1);
1845 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1846
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001847 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1848 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1849 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1850 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1851 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1852 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1853 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001854
1855 return *holder;
1856}
1857
1858
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001859RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001860 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 Context* global_context =
1862 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001863 return global_context->global()->global_receiver();
1864}
1865
1866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001867RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001868 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 ASSERT(args.length() == 4);
1870 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001871 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 Handle<String> pattern = args.at<String>(2);
1873 Handle<String> flags = args.at<String>(3);
1874
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001875 // Get the RegExp function from the context in the literals array.
1876 // This is the RegExp function from the context in which the
1877 // function was created. We do not use the RegExp function from the
1878 // current global context because this might be the RegExp function
1879 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001880 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001881 Handle<JSFunction>(
1882 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001883 // Compute the regular expression literal.
1884 bool has_pending_exception;
1885 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001886 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1887 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001888 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 return Failure::Exception();
1891 }
1892 literals->set(index, *regexp);
1893 return *regexp;
1894}
1895
1896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001897RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001898 NoHandleAllocation ha;
1899 ASSERT(args.length() == 1);
1900
1901 CONVERT_CHECKED(JSFunction, f, args[0]);
1902 return f->shared()->name();
1903}
1904
1905
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001906RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001907 NoHandleAllocation ha;
1908 ASSERT(args.length() == 2);
1909
1910 CONVERT_CHECKED(JSFunction, f, args[0]);
1911 CONVERT_CHECKED(String, name, args[1]);
1912 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001913 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001914}
1915
1916
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001917RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1918 NoHandleAllocation ha;
1919 ASSERT(args.length() == 1);
1920 CONVERT_CHECKED(JSFunction, f, args[0]);
1921 return isolate->heap()->ToBoolean(
1922 f->shared()->name_should_print_as_anonymous());
1923}
1924
1925
1926RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1927 NoHandleAllocation ha;
1928 ASSERT(args.length() == 1);
1929 CONVERT_CHECKED(JSFunction, f, args[0]);
1930 f->shared()->set_name_should_print_as_anonymous(true);
1931 return isolate->heap()->undefined_value();
1932}
1933
1934
whesse@chromium.org7b260152011-06-20 15:33:18 +00001935RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1936 HandleScope scope(isolate);
1937 ASSERT(args.length() == 1);
1938
1939 CONVERT_CHECKED(JSFunction, fun, args[0]);
1940 fun->shared()->set_bound(true);
1941 return isolate->heap()->undefined_value();
1942}
1943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001944RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001945 NoHandleAllocation ha;
1946 ASSERT(args.length() == 1);
1947
1948 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001949 Object* obj = f->RemovePrototype();
1950 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001951
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001952 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001953}
1954
1955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001956RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001957 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 ASSERT(args.length() == 1);
1959
1960 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001961 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1962 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001963
1964 return *GetScriptWrapper(Handle<Script>::cast(script));
1965}
1966
1967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001968RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001969 NoHandleAllocation ha;
1970 ASSERT(args.length() == 1);
1971
1972 CONVERT_CHECKED(JSFunction, f, args[0]);
1973 return f->shared()->GetSourceCode();
1974}
1975
1976
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001978 NoHandleAllocation ha;
1979 ASSERT(args.length() == 1);
1980
1981 CONVERT_CHECKED(JSFunction, fun, args[0]);
1982 int pos = fun->shared()->start_position();
1983 return Smi::FromInt(pos);
1984}
1985
1986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001987RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001988 ASSERT(args.length() == 2);
1989
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001990 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001991 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1992
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001993 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1994
1995 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001996 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001997}
1998
1999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002000RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002001 NoHandleAllocation ha;
2002 ASSERT(args.length() == 2);
2003
2004 CONVERT_CHECKED(JSFunction, fun, args[0]);
2005 CONVERT_CHECKED(String, name, args[1]);
2006 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002007 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008}
2009
2010
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002011RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002012 NoHandleAllocation ha;
2013 ASSERT(args.length() == 2);
2014
2015 CONVERT_CHECKED(JSFunction, fun, args[0]);
2016 CONVERT_CHECKED(Smi, length, args[1]);
2017 fun->shared()->set_length(length->value());
2018 return length;
2019}
2020
2021
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002022// Creates a local, readonly, property called length with the correct
2023// length (when read by the user). This effectively overwrites the
2024// interceptor used to normally provide the length.
2025RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2026 NoHandleAllocation ha;
2027 ASSERT(args.length() == 2);
2028 CONVERT_CHECKED(JSFunction, fun, args[0]);
2029 CONVERT_CHECKED(Smi, length, args[1]);
2030 MaybeObject* maybe_name =
2031 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2032 String* name;
2033 if (!maybe_name->To(&name)) return maybe_name;
2034 PropertyAttributes attr =
2035 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2036 return fun->AddProperty(name, length, attr, kNonStrictMode);
2037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002041 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002042 ASSERT(args.length() == 2);
2043
2044 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002045 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002046 Object* obj;
2047 { MaybeObject* maybe_obj =
2048 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2049 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2050 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051 return args[0]; // return TOS
2052}
2053
2054
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002055RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2056 NoHandleAllocation ha;
2057 RUNTIME_ASSERT(args.length() == 1);
2058 CONVERT_CHECKED(JSFunction, function, args[0]);
2059
2060 MaybeObject* maybe_name =
2061 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2062 String* name;
2063 if (!maybe_name->To(&name)) return maybe_name;
2064
2065 if (function->HasFastProperties()) {
2066 // Construct a new field descriptor with updated attributes.
2067 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2068 int index = instance_desc->Search(name);
2069 ASSERT(index != DescriptorArray::kNotFound);
2070 PropertyDetails details(instance_desc->GetDetails(index));
2071 CallbacksDescriptor new_desc(name,
2072 instance_desc->GetValue(index),
2073 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2074 details.index());
2075 // Construct a new field descriptors array containing the new descriptor.
2076 Object* descriptors_unchecked;
2077 { MaybeObject* maybe_descriptors_unchecked =
2078 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2079 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2080 return maybe_descriptors_unchecked;
2081 }
2082 }
2083 DescriptorArray* new_descriptors =
2084 DescriptorArray::cast(descriptors_unchecked);
2085 // Create a new map featuring the new field descriptors array.
2086 Object* map_unchecked;
2087 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2088 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2089 return maybe_map_unchecked;
2090 }
2091 }
2092 Map* new_map = Map::cast(map_unchecked);
2093 new_map->set_instance_descriptors(new_descriptors);
2094 function->set_map(new_map);
2095 } else { // Dictionary properties.
2096 // Directly manipulate the property details.
2097 int entry = function->property_dictionary()->FindEntry(name);
2098 ASSERT(entry != StringDictionary::kNotFound);
2099 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2100 PropertyDetails new_details(
2101 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2102 details.type(),
2103 details.index());
2104 function->property_dictionary()->DetailsAtPut(entry, new_details);
2105 }
2106 return function;
2107}
2108
2109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002110RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002111 NoHandleAllocation ha;
2112 ASSERT(args.length() == 1);
2113
2114 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002115 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002116}
2117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002119RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002120 NoHandleAllocation ha;
2121 ASSERT(args.length() == 1);
2122
2123 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002124 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002125}
2126
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002128RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002129 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002130 ASSERT(args.length() == 2);
2131
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002132 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002133 Handle<Object> code = args.at<Object>(1);
2134
2135 Handle<Context> context(target->context());
2136
2137 if (!code->IsNull()) {
2138 RUNTIME_ASSERT(code->IsJSFunction());
2139 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002140 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002141
2142 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002143 return Failure::Exception();
2144 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002145 // Since we don't store the source for this we should never
2146 // optimize this.
2147 shared->code()->set_optimizable(false);
2148
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002149 // Set the code, scope info, formal parameter count,
2150 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002151 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002152 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002153 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002154 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002155 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002156 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002157 // Set the source code of the target function to undefined.
2158 // SetCode is only used for built-in constructors like String,
2159 // Array, and Object, and some web code
2160 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002161 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002162 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002163 // Clear the optimization hints related to the compiled code as these are no
2164 // longer valid when the code is overwritten.
2165 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002166 context = Handle<Context>(fun->context());
2167
2168 // Make sure we get a fresh copy of the literal vector to avoid
2169 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002170 int number_of_literals = fun->NumberOfLiterals();
2171 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002172 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002174 // Insert the object, regexp and array functions in the literals
2175 // array prefix. These are the functions that will be used when
2176 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002177 literals->set(JSFunction::kLiteralGlobalContextIndex,
2178 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002179 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002180 // It's okay to skip the write barrier here because the literals
2181 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002182 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002183 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 }
2185
2186 target->set_context(*context);
2187 return *target;
2188}
2189
2190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002191RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002192 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002193 ASSERT(args.length() == 2);
2194 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002195 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002196 RUNTIME_ASSERT(num >= 0);
2197 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002198 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002199}
2200
2201
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002202MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2203 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002204 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002205 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002206 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002207 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002208 }
2209 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002210 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002211}
2212
2213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002214RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002215 NoHandleAllocation ha;
2216 ASSERT(args.length() == 2);
2217
2218 CONVERT_CHECKED(String, subject, args[0]);
2219 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002220 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002221
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002222 uint32_t i = 0;
2223 if (index->IsSmi()) {
2224 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002225 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002226 i = value;
2227 } else {
2228 ASSERT(index->IsHeapNumber());
2229 double value = HeapNumber::cast(index)->value();
2230 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002231 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002232
2233 // Flatten the string. If someone wants to get a char at an index
2234 // in a cons string, it is likely that more indices will be
2235 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002236 Object* flat;
2237 { MaybeObject* maybe_flat = subject->TryFlatten();
2238 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2239 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002240 subject = String::cast(flat);
2241
2242 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002244 }
2245
2246 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002247}
2248
2249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002250RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251 NoHandleAllocation ha;
2252 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002253 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002254}
2255
lrn@chromium.org25156de2010-04-06 13:10:27 +00002256
2257class FixedArrayBuilder {
2258 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002259 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2260 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002261 length_(0) {
2262 // Require a non-zero initial size. Ensures that doubling the size to
2263 // extend the array will work.
2264 ASSERT(initial_capacity > 0);
2265 }
2266
2267 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2268 : array_(backing_store),
2269 length_(0) {
2270 // Require a non-zero initial size. Ensures that doubling the size to
2271 // extend the array will work.
2272 ASSERT(backing_store->length() > 0);
2273 }
2274
2275 bool HasCapacity(int elements) {
2276 int length = array_->length();
2277 int required_length = length_ + elements;
2278 return (length >= required_length);
2279 }
2280
2281 void EnsureCapacity(int elements) {
2282 int length = array_->length();
2283 int required_length = length_ + elements;
2284 if (length < required_length) {
2285 int new_length = length;
2286 do {
2287 new_length *= 2;
2288 } while (new_length < required_length);
2289 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002291 array_->CopyTo(0, *extended_array, 0, length_);
2292 array_ = extended_array;
2293 }
2294 }
2295
2296 void Add(Object* value) {
2297 ASSERT(length_ < capacity());
2298 array_->set(length_, value);
2299 length_++;
2300 }
2301
2302 void Add(Smi* value) {
2303 ASSERT(length_ < capacity());
2304 array_->set(length_, value);
2305 length_++;
2306 }
2307
2308 Handle<FixedArray> array() {
2309 return array_;
2310 }
2311
2312 int length() {
2313 return length_;
2314 }
2315
2316 int capacity() {
2317 return array_->length();
2318 }
2319
2320 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002321 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002322 result_array->set_length(Smi::FromInt(length_));
2323 return result_array;
2324 }
2325
2326 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2327 target_array->set_elements(*array_);
2328 target_array->set_length(Smi::FromInt(length_));
2329 return target_array;
2330 }
2331
2332 private:
2333 Handle<FixedArray> array_;
2334 int length_;
2335};
2336
2337
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002338// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002339const int kStringBuilderConcatHelperLengthBits = 11;
2340const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002341
2342template <typename schar>
2343static inline void StringBuilderConcatHelper(String*,
2344 schar*,
2345 FixedArray*,
2346 int);
2347
lrn@chromium.org25156de2010-04-06 13:10:27 +00002348typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2349 StringBuilderSubstringLength;
2350typedef BitField<int,
2351 kStringBuilderConcatHelperLengthBits,
2352 kStringBuilderConcatHelperPositionBits>
2353 StringBuilderSubstringPosition;
2354
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002355
2356class ReplacementStringBuilder {
2357 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002358 ReplacementStringBuilder(Heap* heap,
2359 Handle<String> subject,
2360 int estimated_part_count)
2361 : heap_(heap),
2362 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002363 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002364 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002365 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002366 // Require a non-zero initial size. Ensures that doubling the size to
2367 // extend the array will work.
2368 ASSERT(estimated_part_count > 0);
2369 }
2370
lrn@chromium.org25156de2010-04-06 13:10:27 +00002371 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2372 int from,
2373 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374 ASSERT(from >= 0);
2375 int length = to - from;
2376 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002377 if (StringBuilderSubstringLength::is_valid(length) &&
2378 StringBuilderSubstringPosition::is_valid(from)) {
2379 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2380 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002382 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002383 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002384 builder->Add(Smi::FromInt(-length));
2385 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002386 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002387 }
2388
2389
2390 void EnsureCapacity(int elements) {
2391 array_builder_.EnsureCapacity(elements);
2392 }
2393
2394
2395 void AddSubjectSlice(int from, int to) {
2396 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002397 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002398 }
2399
2400
2401 void AddString(Handle<String> string) {
2402 int length = string->length();
2403 ASSERT(length > 0);
2404 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002405 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 is_ascii_ = false;
2407 }
2408 IncrementCharacterCount(length);
2409 }
2410
2411
2412 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002414 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 }
2416
2417 Handle<String> joined_string;
2418 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002419 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002420 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002421 char* char_buffer = seq->GetChars();
2422 StringBuilderConcatHelper(*subject_,
2423 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002424 *array_builder_.array(),
2425 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002426 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 } else {
2428 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002429 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002430 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002431 uc16* char_buffer = seq->GetChars();
2432 StringBuilderConcatHelper(*subject_,
2433 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002434 *array_builder_.array(),
2435 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002436 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002437 }
2438 return joined_string;
2439 }
2440
2441
2442 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002443 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 V8::FatalProcessOutOfMemory("String.replace result too large.");
2445 }
2446 character_count_ += by;
2447 }
2448
lrn@chromium.org25156de2010-04-06 13:10:27 +00002449 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002450 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002451 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002452
lrn@chromium.org25156de2010-04-06 13:10:27 +00002453 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002454 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2455 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 }
2457
2458
ager@chromium.org04921a82011-06-27 13:21:41 +00002459 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2460 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002461 }
2462
2463
2464 void AddElement(Object* element) {
2465 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002466 ASSERT(array_builder_.capacity() > array_builder_.length());
2467 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 }
2469
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002470 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002471 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002472 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 int character_count_;
2474 bool is_ascii_;
2475};
2476
2477
2478class CompiledReplacement {
2479 public:
2480 CompiledReplacement()
2481 : parts_(1), replacement_substrings_(0) {}
2482
2483 void Compile(Handle<String> replacement,
2484 int capture_count,
2485 int subject_length);
2486
2487 void Apply(ReplacementStringBuilder* builder,
2488 int match_from,
2489 int match_to,
2490 Handle<JSArray> last_match_info);
2491
2492 // Number of distinct parts of the replacement pattern.
2493 int parts() {
2494 return parts_.length();
2495 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002496
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 private:
2498 enum PartType {
2499 SUBJECT_PREFIX = 1,
2500 SUBJECT_SUFFIX,
2501 SUBJECT_CAPTURE,
2502 REPLACEMENT_SUBSTRING,
2503 REPLACEMENT_STRING,
2504
2505 NUMBER_OF_PART_TYPES
2506 };
2507
2508 struct ReplacementPart {
2509 static inline ReplacementPart SubjectMatch() {
2510 return ReplacementPart(SUBJECT_CAPTURE, 0);
2511 }
2512 static inline ReplacementPart SubjectCapture(int capture_index) {
2513 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2514 }
2515 static inline ReplacementPart SubjectPrefix() {
2516 return ReplacementPart(SUBJECT_PREFIX, 0);
2517 }
2518 static inline ReplacementPart SubjectSuffix(int subject_length) {
2519 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2520 }
2521 static inline ReplacementPart ReplacementString() {
2522 return ReplacementPart(REPLACEMENT_STRING, 0);
2523 }
2524 static inline ReplacementPart ReplacementSubString(int from, int to) {
2525 ASSERT(from >= 0);
2526 ASSERT(to > from);
2527 return ReplacementPart(-from, to);
2528 }
2529
2530 // If tag <= 0 then it is the negation of a start index of a substring of
2531 // the replacement pattern, otherwise it's a value from PartType.
2532 ReplacementPart(int tag, int data)
2533 : tag(tag), data(data) {
2534 // Must be non-positive or a PartType value.
2535 ASSERT(tag < NUMBER_OF_PART_TYPES);
2536 }
2537 // Either a value of PartType or a non-positive number that is
2538 // the negation of an index into the replacement string.
2539 int tag;
2540 // The data value's interpretation depends on the value of tag:
2541 // tag == SUBJECT_PREFIX ||
2542 // tag == SUBJECT_SUFFIX: data is unused.
2543 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2544 // tag == REPLACEMENT_SUBSTRING ||
2545 // tag == REPLACEMENT_STRING: data is index into array of substrings
2546 // of the replacement string.
2547 // tag <= 0: Temporary representation of the substring of the replacement
2548 // string ranging over -tag .. data.
2549 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2550 // substring objects.
2551 int data;
2552 };
2553
2554 template<typename Char>
2555 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2556 Vector<Char> characters,
2557 int capture_count,
2558 int subject_length) {
2559 int length = characters.length();
2560 int last = 0;
2561 for (int i = 0; i < length; i++) {
2562 Char c = characters[i];
2563 if (c == '$') {
2564 int next_index = i + 1;
2565 if (next_index == length) { // No next character!
2566 break;
2567 }
2568 Char c2 = characters[next_index];
2569 switch (c2) {
2570 case '$':
2571 if (i > last) {
2572 // There is a substring before. Include the first "$".
2573 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2574 last = next_index + 1; // Continue after the second "$".
2575 } else {
2576 // Let the next substring start with the second "$".
2577 last = next_index;
2578 }
2579 i = next_index;
2580 break;
2581 case '`':
2582 if (i > last) {
2583 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2584 }
2585 parts->Add(ReplacementPart::SubjectPrefix());
2586 i = next_index;
2587 last = i + 1;
2588 break;
2589 case '\'':
2590 if (i > last) {
2591 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2592 }
2593 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2594 i = next_index;
2595 last = i + 1;
2596 break;
2597 case '&':
2598 if (i > last) {
2599 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2600 }
2601 parts->Add(ReplacementPart::SubjectMatch());
2602 i = next_index;
2603 last = i + 1;
2604 break;
2605 case '0':
2606 case '1':
2607 case '2':
2608 case '3':
2609 case '4':
2610 case '5':
2611 case '6':
2612 case '7':
2613 case '8':
2614 case '9': {
2615 int capture_ref = c2 - '0';
2616 if (capture_ref > capture_count) {
2617 i = next_index;
2618 continue;
2619 }
2620 int second_digit_index = next_index + 1;
2621 if (second_digit_index < length) {
2622 // Peek ahead to see if we have two digits.
2623 Char c3 = characters[second_digit_index];
2624 if ('0' <= c3 && c3 <= '9') { // Double digits.
2625 int double_digit_ref = capture_ref * 10 + c3 - '0';
2626 if (double_digit_ref <= capture_count) {
2627 next_index = second_digit_index;
2628 capture_ref = double_digit_ref;
2629 }
2630 }
2631 }
2632 if (capture_ref > 0) {
2633 if (i > last) {
2634 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2635 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002636 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002637 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2638 last = next_index + 1;
2639 }
2640 i = next_index;
2641 break;
2642 }
2643 default:
2644 i = next_index;
2645 break;
2646 }
2647 }
2648 }
2649 if (length > last) {
2650 if (last == 0) {
2651 parts->Add(ReplacementPart::ReplacementString());
2652 } else {
2653 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2654 }
2655 }
2656 }
2657
2658 ZoneList<ReplacementPart> parts_;
2659 ZoneList<Handle<String> > replacement_substrings_;
2660};
2661
2662
2663void CompiledReplacement::Compile(Handle<String> replacement,
2664 int capture_count,
2665 int subject_length) {
2666 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002667 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002668 AssertNoAllocation no_alloc;
2669 ParseReplacementPattern(&parts_,
2670 replacement->ToAsciiVector(),
2671 capture_count,
2672 subject_length);
2673 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002674 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002675 AssertNoAllocation no_alloc;
2676
2677 ParseReplacementPattern(&parts_,
2678 replacement->ToUC16Vector(),
2679 capture_count,
2680 subject_length);
2681 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002682 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002683 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002684 int substring_index = 0;
2685 for (int i = 0, n = parts_.length(); i < n; i++) {
2686 int tag = parts_[i].tag;
2687 if (tag <= 0) { // A replacement string slice.
2688 int from = -tag;
2689 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002690 replacement_substrings_.Add(
2691 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002692 parts_[i].tag = REPLACEMENT_SUBSTRING;
2693 parts_[i].data = substring_index;
2694 substring_index++;
2695 } else if (tag == REPLACEMENT_STRING) {
2696 replacement_substrings_.Add(replacement);
2697 parts_[i].data = substring_index;
2698 substring_index++;
2699 }
2700 }
2701}
2702
2703
2704void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2705 int match_from,
2706 int match_to,
2707 Handle<JSArray> last_match_info) {
2708 for (int i = 0, n = parts_.length(); i < n; i++) {
2709 ReplacementPart part = parts_[i];
2710 switch (part.tag) {
2711 case SUBJECT_PREFIX:
2712 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2713 break;
2714 case SUBJECT_SUFFIX: {
2715 int subject_length = part.data;
2716 if (match_to < subject_length) {
2717 builder->AddSubjectSlice(match_to, subject_length);
2718 }
2719 break;
2720 }
2721 case SUBJECT_CAPTURE: {
2722 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002723 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002724 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2725 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2726 if (from >= 0 && to > from) {
2727 builder->AddSubjectSlice(from, to);
2728 }
2729 break;
2730 }
2731 case REPLACEMENT_SUBSTRING:
2732 case REPLACEMENT_STRING:
2733 builder->AddString(replacement_substrings_[part.data]);
2734 break;
2735 default:
2736 UNREACHABLE();
2737 }
2738 }
2739}
2740
2741
2742
lrn@chromium.org303ada72010-10-27 09:33:13 +00002743MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002744 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002745 String* subject,
2746 JSRegExp* regexp,
2747 String* replacement,
2748 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002749 ASSERT(subject->IsFlat());
2750 ASSERT(replacement->IsFlat());
2751
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002752 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002753
2754 int length = subject->length();
2755 Handle<String> subject_handle(subject);
2756 Handle<JSRegExp> regexp_handle(regexp);
2757 Handle<String> replacement_handle(replacement);
2758 Handle<JSArray> last_match_info_handle(last_match_info);
2759 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2760 subject_handle,
2761 0,
2762 last_match_info_handle);
2763 if (match.is_null()) {
2764 return Failure::Exception();
2765 }
2766 if (match->IsNull()) {
2767 return *subject_handle;
2768 }
2769
2770 int capture_count = regexp_handle->CaptureCount();
2771
2772 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002773 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002774 CompiledReplacement compiled_replacement;
2775 compiled_replacement.Compile(replacement_handle,
2776 capture_count,
2777 length);
2778
2779 bool is_global = regexp_handle->GetFlags().is_global();
2780
2781 // Guessing the number of parts that the final result string is built
2782 // from. Global regexps can match any number of times, so we guess
2783 // conservatively.
2784 int expected_parts =
2785 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002786 ReplacementStringBuilder builder(isolate->heap(),
2787 subject_handle,
2788 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002789
2790 // Index of end of last match.
2791 int prev = 0;
2792
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002793 // Number of parts added by compiled replacement plus preceeding
2794 // string and possibly suffix after last match. It is possible for
2795 // all components to use two elements when encoded as two smis.
2796 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002797 bool matched = true;
2798 do {
2799 ASSERT(last_match_info_handle->HasFastElements());
2800 // Increase the capacity of the builder before entering local handle-scope,
2801 // so its internal buffer can safely allocate a new handle if it grows.
2802 builder.EnsureCapacity(parts_added_per_loop);
2803
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002804 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002805 int start, end;
2806 {
2807 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002808 FixedArray* match_info_array =
2809 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002810
2811 ASSERT_EQ(capture_count * 2 + 2,
2812 RegExpImpl::GetLastCaptureCount(match_info_array));
2813 start = RegExpImpl::GetCapture(match_info_array, 0);
2814 end = RegExpImpl::GetCapture(match_info_array, 1);
2815 }
2816
2817 if (prev < start) {
2818 builder.AddSubjectSlice(prev, start);
2819 }
2820 compiled_replacement.Apply(&builder,
2821 start,
2822 end,
2823 last_match_info_handle);
2824 prev = end;
2825
2826 // Only continue checking for global regexps.
2827 if (!is_global) break;
2828
2829 // Continue from where the match ended, unless it was an empty match.
2830 int next = end;
2831 if (start == end) {
2832 next = end + 1;
2833 if (next > length) break;
2834 }
2835
2836 match = RegExpImpl::Exec(regexp_handle,
2837 subject_handle,
2838 next,
2839 last_match_info_handle);
2840 if (match.is_null()) {
2841 return Failure::Exception();
2842 }
2843 matched = !match->IsNull();
2844 } while (matched);
2845
2846 if (prev < length) {
2847 builder.AddSubjectSlice(prev, length);
2848 }
2849
2850 return *(builder.ToString());
2851}
2852
2853
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002854template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002855MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002856 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002857 String* subject,
2858 JSRegExp* regexp,
2859 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002860 ASSERT(subject->IsFlat());
2861
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002862 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002863
2864 Handle<String> subject_handle(subject);
2865 Handle<JSRegExp> regexp_handle(regexp);
2866 Handle<JSArray> last_match_info_handle(last_match_info);
2867 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2868 subject_handle,
2869 0,
2870 last_match_info_handle);
2871 if (match.is_null()) return Failure::Exception();
2872 if (match->IsNull()) return *subject_handle;
2873
2874 ASSERT(last_match_info_handle->HasFastElements());
2875
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002876 int start, end;
2877 {
2878 AssertNoAllocation match_info_array_is_not_in_a_handle;
2879 FixedArray* match_info_array =
2880 FixedArray::cast(last_match_info_handle->elements());
2881
2882 start = RegExpImpl::GetCapture(match_info_array, 0);
2883 end = RegExpImpl::GetCapture(match_info_array, 1);
2884 }
2885
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002886 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002887 int new_length = length - (end - start);
2888 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002889 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002890 }
2891 Handle<ResultSeqString> answer;
2892 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002893 answer = Handle<ResultSeqString>::cast(
2894 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002895 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002896 answer = Handle<ResultSeqString>::cast(
2897 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002898 }
2899
2900 // If the regexp isn't global, only match once.
2901 if (!regexp_handle->GetFlags().is_global()) {
2902 if (start > 0) {
2903 String::WriteToFlat(*subject_handle,
2904 answer->GetChars(),
2905 0,
2906 start);
2907 }
2908 if (end < length) {
2909 String::WriteToFlat(*subject_handle,
2910 answer->GetChars() + start,
2911 end,
2912 length);
2913 }
2914 return *answer;
2915 }
2916
2917 int prev = 0; // Index of end of last match.
2918 int next = 0; // Start of next search (prev unless last match was empty).
2919 int position = 0;
2920
2921 do {
2922 if (prev < start) {
2923 // Add substring subject[prev;start] to answer string.
2924 String::WriteToFlat(*subject_handle,
2925 answer->GetChars() + position,
2926 prev,
2927 start);
2928 position += start - prev;
2929 }
2930 prev = end;
2931 next = end;
2932 // Continue from where the match ended, unless it was an empty match.
2933 if (start == end) {
2934 next++;
2935 if (next > length) break;
2936 }
2937 match = RegExpImpl::Exec(regexp_handle,
2938 subject_handle,
2939 next,
2940 last_match_info_handle);
2941 if (match.is_null()) return Failure::Exception();
2942 if (match->IsNull()) break;
2943
2944 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002945 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002946 {
2947 AssertNoAllocation match_info_array_is_not_in_a_handle;
2948 FixedArray* match_info_array =
2949 FixedArray::cast(last_match_info_handle->elements());
2950 start = RegExpImpl::GetCapture(match_info_array, 0);
2951 end = RegExpImpl::GetCapture(match_info_array, 1);
2952 }
2953 } while (true);
2954
2955 if (prev < length) {
2956 // Add substring subject[prev;length] to answer string.
2957 String::WriteToFlat(*subject_handle,
2958 answer->GetChars() + position,
2959 prev,
2960 length);
2961 position += length - prev;
2962 }
2963
2964 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002965 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002966 }
2967
2968 // Shorten string and fill
2969 int string_size = ResultSeqString::SizeFor(position);
2970 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2971 int delta = allocated_string_size - string_size;
2972
2973 answer->set_length(position);
2974 if (delta == 0) return *answer;
2975
2976 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002977 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002978
2979 return *answer;
2980}
2981
2982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002983RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002984 ASSERT(args.length() == 4);
2985
2986 CONVERT_CHECKED(String, subject, args[0]);
2987 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002988 Object* flat_subject;
2989 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2990 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2991 return maybe_flat_subject;
2992 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002993 }
2994 subject = String::cast(flat_subject);
2995 }
2996
2997 CONVERT_CHECKED(String, replacement, args[2]);
2998 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002999 Object* flat_replacement;
3000 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3001 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3002 return maybe_flat_replacement;
3003 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003004 }
3005 replacement = String::cast(flat_replacement);
3006 }
3007
3008 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3009 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3010
3011 ASSERT(last_match_info->HasFastElements());
3012
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003013 if (replacement->length() == 0) {
3014 if (subject->HasOnlyAsciiChars()) {
3015 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003016 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003017 } else {
3018 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003019 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003020 }
3021 }
3022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003023 return StringReplaceRegExpWithString(isolate,
3024 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003025 regexp,
3026 replacement,
3027 last_match_info);
3028}
3029
3030
ager@chromium.org7c537e22008-10-16 08:43:32 +00003031// Perform string match of pattern on subject, starting at start index.
3032// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003033// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003034int Runtime::StringMatch(Isolate* isolate,
3035 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003036 Handle<String> pat,
3037 int start_index) {
3038 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003039 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003040
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003041 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003042 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003043
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003044 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003045 if (start_index + pattern_length > subject_length) return -1;
3046
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003047 if (!sub->IsFlat()) FlattenString(sub);
3048 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003049
ager@chromium.org7c537e22008-10-16 08:43:32 +00003050 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003051 // Extract flattened substrings of cons strings before determining asciiness.
3052 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003053 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003054 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003055 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003056
ager@chromium.org7c537e22008-10-16 08:43:32 +00003057 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003058 if (seq_pat->IsAsciiRepresentation()) {
3059 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
3060 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003061 return SearchString(isolate,
3062 seq_sub->ToAsciiVector(),
3063 pat_vector,
3064 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003065 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003066 return SearchString(isolate,
3067 seq_sub->ToUC16Vector(),
3068 pat_vector,
3069 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003070 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003071 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
3072 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003073 return SearchString(isolate,
3074 seq_sub->ToAsciiVector(),
3075 pat_vector,
3076 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003077 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003078 return SearchString(isolate,
3079 seq_sub->ToUC16Vector(),
3080 pat_vector,
3081 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003082}
3083
3084
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003085RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003086 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003087 ASSERT(args.length() == 3);
3088
ager@chromium.org7c537e22008-10-16 08:43:32 +00003089 CONVERT_ARG_CHECKED(String, sub, 0);
3090 CONVERT_ARG_CHECKED(String, pat, 1);
3091
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003092 Object* index = args[2];
3093 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003094 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003095
ager@chromium.org870a0b62008-11-04 11:43:05 +00003096 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003097 int position =
3098 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003099 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003100}
3101
3102
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003103template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003104static int StringMatchBackwards(Vector<const schar> subject,
3105 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003106 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003107 int pattern_length = pattern.length();
3108 ASSERT(pattern_length >= 1);
3109 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003110
3111 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003112 for (int i = 0; i < pattern_length; i++) {
3113 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003114 if (c > String::kMaxAsciiCharCode) {
3115 return -1;
3116 }
3117 }
3118 }
3119
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003120 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003121 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003122 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003123 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003124 while (j < pattern_length) {
3125 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003126 break;
3127 }
3128 j++;
3129 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003130 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003131 return i;
3132 }
3133 }
3134 return -1;
3135}
3136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003137RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003139 ASSERT(args.length() == 3);
3140
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003141 CONVERT_ARG_CHECKED(String, sub, 0);
3142 CONVERT_ARG_CHECKED(String, pat, 1);
3143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003144 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003145 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003146 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003147
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003148 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003149 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003150
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003151 if (start_index + pat_length > sub_length) {
3152 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003153 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003154
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003155 if (pat_length == 0) {
3156 return Smi::FromInt(start_index);
3157 }
3158
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003159 if (!sub->IsFlat()) FlattenString(sub);
3160 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003161
3162 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3163
3164 int position = -1;
3165
3166 if (pat->IsAsciiRepresentation()) {
3167 Vector<const char> pat_vector = pat->ToAsciiVector();
3168 if (sub->IsAsciiRepresentation()) {
3169 position = StringMatchBackwards(sub->ToAsciiVector(),
3170 pat_vector,
3171 start_index);
3172 } else {
3173 position = StringMatchBackwards(sub->ToUC16Vector(),
3174 pat_vector,
3175 start_index);
3176 }
3177 } else {
3178 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3179 if (sub->IsAsciiRepresentation()) {
3180 position = StringMatchBackwards(sub->ToAsciiVector(),
3181 pat_vector,
3182 start_index);
3183 } else {
3184 position = StringMatchBackwards(sub->ToUC16Vector(),
3185 pat_vector,
3186 start_index);
3187 }
3188 }
3189
3190 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003191}
3192
3193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003194RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003195 NoHandleAllocation ha;
3196 ASSERT(args.length() == 2);
3197
3198 CONVERT_CHECKED(String, str1, args[0]);
3199 CONVERT_CHECKED(String, str2, args[1]);
3200
3201 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003202 int str1_length = str1->length();
3203 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003204
3205 // Decide trivial cases without flattening.
3206 if (str1_length == 0) {
3207 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3208 return Smi::FromInt(-str2_length);
3209 } else {
3210 if (str2_length == 0) return Smi::FromInt(str1_length);
3211 }
3212
3213 int end = str1_length < str2_length ? str1_length : str2_length;
3214
3215 // No need to flatten if we are going to find the answer on the first
3216 // character. At this point we know there is at least one character
3217 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003218 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003219 if (d != 0) return Smi::FromInt(d);
3220
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003221 str1->TryFlatten();
3222 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003224 StringInputBuffer& buf1 =
3225 *isolate->runtime_state()->string_locale_compare_buf1();
3226 StringInputBuffer& buf2 =
3227 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003228
3229 buf1.Reset(str1);
3230 buf2.Reset(str2);
3231
3232 for (int i = 0; i < end; i++) {
3233 uint16_t char1 = buf1.GetNext();
3234 uint16_t char2 = buf2.GetNext();
3235 if (char1 != char2) return Smi::FromInt(char1 - char2);
3236 }
3237
3238 return Smi::FromInt(str1_length - str2_length);
3239}
3240
3241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003242RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003243 NoHandleAllocation ha;
3244 ASSERT(args.length() == 3);
3245
3246 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003247 int start, end;
3248 // We have a fast integer-only case here to avoid a conversion to double in
3249 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003250 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3251 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3252 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3253 start = from_number;
3254 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003255 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003256 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3257 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003258 start = FastD2I(from_number);
3259 end = FastD2I(to_number);
3260 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003261 RUNTIME_ASSERT(end >= start);
3262 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003263 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003264 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003265 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003266}
3267
3268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003269RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003270 ASSERT_EQ(3, args.length());
3271
3272 CONVERT_ARG_CHECKED(String, subject, 0);
3273 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3274 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3275 HandleScope handles;
3276
3277 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3278
3279 if (match.is_null()) {
3280 return Failure::Exception();
3281 }
3282 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003283 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003284 }
3285 int length = subject->length();
3286
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003287 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003288 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003289 int start;
3290 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003291 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003292 {
3293 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003294 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003295 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3296 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3297 }
3298 offsets.Add(start);
3299 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003300 if (start == end) if (++end > length) break;
3301 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003302 if (match.is_null()) {
3303 return Failure::Exception();
3304 }
3305 } while (!match->IsNull());
3306 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003307 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003308 Handle<String> substring = isolate->factory()->
3309 NewSubString(subject, offsets.at(0), offsets.at(1));
3310 elements->set(0, *substring);
3311 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003312 int from = offsets.at(i * 2);
3313 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003314 Handle<String> substring = isolate->factory()->
3315 NewProperSubString(subject, from, to);
3316 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003317 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003318 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003319 result->set_length(Smi::FromInt(matches));
3320 return *result;
3321}
3322
3323
lrn@chromium.org25156de2010-04-06 13:10:27 +00003324// Two smis before and after the match, for very long strings.
3325const int kMaxBuilderEntriesPerRegExpMatch = 5;
3326
3327
3328static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3329 Handle<JSArray> last_match_info,
3330 int match_start,
3331 int match_end) {
3332 // Fill last_match_info with a single capture.
3333 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3334 AssertNoAllocation no_gc;
3335 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3336 RegExpImpl::SetLastCaptureCount(elements, 2);
3337 RegExpImpl::SetLastInput(elements, *subject);
3338 RegExpImpl::SetLastSubject(elements, *subject);
3339 RegExpImpl::SetCapture(elements, 0, match_start);
3340 RegExpImpl::SetCapture(elements, 1, match_end);
3341}
3342
3343
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003344template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003345static bool SearchStringMultiple(Isolate* isolate,
3346 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003347 Vector<const PatternChar> pattern,
3348 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003349 FixedArrayBuilder* builder,
3350 int* match_pos) {
3351 int pos = *match_pos;
3352 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003353 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003354 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003355 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003356 while (pos <= max_search_start) {
3357 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3358 *match_pos = pos;
3359 return false;
3360 }
3361 // Position of end of previous match.
3362 int match_end = pos + pattern_length;
3363 int new_pos = search.Search(subject, match_end);
3364 if (new_pos >= 0) {
3365 // A match.
3366 if (new_pos > match_end) {
3367 ReplacementStringBuilder::AddSubjectSlice(builder,
3368 match_end,
3369 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003370 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003371 pos = new_pos;
3372 builder->Add(pattern_string);
3373 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003374 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003375 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003376 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003377
lrn@chromium.org25156de2010-04-06 13:10:27 +00003378 if (pos < max_search_start) {
3379 ReplacementStringBuilder::AddSubjectSlice(builder,
3380 pos + pattern_length,
3381 subject_length);
3382 }
3383 *match_pos = pos;
3384 return true;
3385}
3386
3387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003388static bool SearchStringMultiple(Isolate* isolate,
3389 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003390 Handle<String> pattern,
3391 Handle<JSArray> last_match_info,
3392 FixedArrayBuilder* builder) {
3393 ASSERT(subject->IsFlat());
3394 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003395
3396 // Treating as if a previous match was before first character.
3397 int match_pos = -pattern->length();
3398
3399 for (;;) { // Break when search complete.
3400 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3401 AssertNoAllocation no_gc;
3402 if (subject->IsAsciiRepresentation()) {
3403 Vector<const char> subject_vector = subject->ToAsciiVector();
3404 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003405 if (SearchStringMultiple(isolate,
3406 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003407 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003408 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003409 builder,
3410 &match_pos)) break;
3411 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003412 if (SearchStringMultiple(isolate,
3413 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003414 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003415 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003416 builder,
3417 &match_pos)) break;
3418 }
3419 } else {
3420 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3421 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003422 if (SearchStringMultiple(isolate,
3423 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003424 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003425 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003426 builder,
3427 &match_pos)) break;
3428 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003429 if (SearchStringMultiple(isolate,
3430 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003431 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003432 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003433 builder,
3434 &match_pos)) break;
3435 }
3436 }
3437 }
3438
3439 if (match_pos >= 0) {
3440 SetLastMatchInfoNoCaptures(subject,
3441 last_match_info,
3442 match_pos,
3443 match_pos + pattern->length());
3444 return true;
3445 }
3446 return false; // No matches at all.
3447}
3448
3449
3450static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003451 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003452 Handle<String> subject,
3453 Handle<JSRegExp> regexp,
3454 Handle<JSArray> last_match_array,
3455 FixedArrayBuilder* builder) {
3456 ASSERT(subject->IsFlat());
3457 int match_start = -1;
3458 int match_end = 0;
3459 int pos = 0;
3460 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3461 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3462
3463 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003464 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003465 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003466 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003467
3468 for (;;) { // Break on failure, return on exception.
3469 RegExpImpl::IrregexpResult result =
3470 RegExpImpl::IrregexpExecOnce(regexp,
3471 subject,
3472 pos,
3473 register_vector);
3474 if (result == RegExpImpl::RE_SUCCESS) {
3475 match_start = register_vector[0];
3476 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3477 if (match_end < match_start) {
3478 ReplacementStringBuilder::AddSubjectSlice(builder,
3479 match_end,
3480 match_start);
3481 }
3482 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003483 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003484 if (!first) {
3485 builder->Add(*isolate->factory()->NewProperSubString(subject,
3486 match_start,
3487 match_end));
3488 } else {
3489 builder->Add(*isolate->factory()->NewSubString(subject,
3490 match_start,
3491 match_end));
3492 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003493 if (match_start != match_end) {
3494 pos = match_end;
3495 } else {
3496 pos = match_end + 1;
3497 if (pos > subject_length) break;
3498 }
3499 } else if (result == RegExpImpl::RE_FAILURE) {
3500 break;
3501 } else {
3502 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3503 return result;
3504 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003505 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003506 }
3507
3508 if (match_start >= 0) {
3509 if (match_end < subject_length) {
3510 ReplacementStringBuilder::AddSubjectSlice(builder,
3511 match_end,
3512 subject_length);
3513 }
3514 SetLastMatchInfoNoCaptures(subject,
3515 last_match_array,
3516 match_start,
3517 match_end);
3518 return RegExpImpl::RE_SUCCESS;
3519 } else {
3520 return RegExpImpl::RE_FAILURE; // No matches at all.
3521 }
3522}
3523
3524
3525static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003526 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003527 Handle<String> subject,
3528 Handle<JSRegExp> regexp,
3529 Handle<JSArray> last_match_array,
3530 FixedArrayBuilder* builder) {
3531
3532 ASSERT(subject->IsFlat());
3533 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3534 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3535
3536 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003537 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003538
3539 RegExpImpl::IrregexpResult result =
3540 RegExpImpl::IrregexpExecOnce(regexp,
3541 subject,
3542 0,
3543 register_vector);
3544
3545 int capture_count = regexp->CaptureCount();
3546 int subject_length = subject->length();
3547
3548 // Position to search from.
3549 int pos = 0;
3550 // End of previous match. Differs from pos if match was empty.
3551 int match_end = 0;
3552 if (result == RegExpImpl::RE_SUCCESS) {
3553 // Need to keep a copy of the previous match for creating last_match_info
3554 // at the end, so we have two vectors that we swap between.
3555 OffsetsVector registers2(required_registers);
3556 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003557 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003558 do {
3559 int match_start = register_vector[0];
3560 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3561 if (match_end < match_start) {
3562 ReplacementStringBuilder::AddSubjectSlice(builder,
3563 match_end,
3564 match_start);
3565 }
3566 match_end = register_vector[1];
3567
3568 {
3569 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003570 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003571 // Arguments array to replace function is match, captures, index and
3572 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003573 Handle<FixedArray> elements =
3574 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003575 Handle<String> match;
3576 if (!first) {
3577 match = isolate->factory()->NewProperSubString(subject,
3578 match_start,
3579 match_end);
3580 } else {
3581 match = isolate->factory()->NewSubString(subject,
3582 match_start,
3583 match_end);
3584 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003585 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003586 for (int i = 1; i <= capture_count; i++) {
3587 int start = register_vector[i * 2];
3588 if (start >= 0) {
3589 int end = register_vector[i * 2 + 1];
3590 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003591 Handle<String> substring;
3592 if (!first) {
3593 substring = isolate->factory()->NewProperSubString(subject,
3594 start,
3595 end);
3596 } else {
3597 substring = isolate->factory()->NewSubString(subject, start, end);
3598 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003599 elements->set(i, *substring);
3600 } else {
3601 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003603 }
3604 }
3605 elements->set(capture_count + 1, Smi::FromInt(match_start));
3606 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003607 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003608 }
3609 // Swap register vectors, so the last successful match is in
3610 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003611 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003612 prev_register_vector = register_vector;
3613 register_vector = tmp;
3614
3615 if (match_end > match_start) {
3616 pos = match_end;
3617 } else {
3618 pos = match_end + 1;
3619 if (pos > subject_length) {
3620 break;
3621 }
3622 }
3623
3624 result = RegExpImpl::IrregexpExecOnce(regexp,
3625 subject,
3626 pos,
3627 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003628 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003629 } while (result == RegExpImpl::RE_SUCCESS);
3630
3631 if (result != RegExpImpl::RE_EXCEPTION) {
3632 // Finished matching, with at least one match.
3633 if (match_end < subject_length) {
3634 ReplacementStringBuilder::AddSubjectSlice(builder,
3635 match_end,
3636 subject_length);
3637 }
3638
3639 int last_match_capture_count = (capture_count + 1) * 2;
3640 int last_match_array_size =
3641 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3642 last_match_array->EnsureSize(last_match_array_size);
3643 AssertNoAllocation no_gc;
3644 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3645 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3646 RegExpImpl::SetLastSubject(elements, *subject);
3647 RegExpImpl::SetLastInput(elements, *subject);
3648 for (int i = 0; i < last_match_capture_count; i++) {
3649 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3650 }
3651 return RegExpImpl::RE_SUCCESS;
3652 }
3653 }
3654 // No matches at all, return failure or exception result directly.
3655 return result;
3656}
3657
3658
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003659RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003660 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003661 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003662
3663 CONVERT_ARG_CHECKED(String, subject, 1);
3664 if (!subject->IsFlat()) { FlattenString(subject); }
3665 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3666 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3667 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3668
3669 ASSERT(last_match_info->HasFastElements());
3670 ASSERT(regexp->GetFlags().is_global());
3671 Handle<FixedArray> result_elements;
3672 if (result_array->HasFastElements()) {
3673 result_elements =
3674 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003675 }
3676 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003678 }
3679 FixedArrayBuilder builder(result_elements);
3680
3681 if (regexp->TypeTag() == JSRegExp::ATOM) {
3682 Handle<String> pattern(
3683 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003684 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 if (SearchStringMultiple(isolate, subject, pattern,
3686 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003687 return *builder.ToJSArray(result_array);
3688 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003689 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003690 }
3691
3692 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3693
3694 RegExpImpl::IrregexpResult result;
3695 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003696 result = SearchRegExpNoCaptureMultiple(isolate,
3697 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003698 regexp,
3699 last_match_info,
3700 &builder);
3701 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003702 result = SearchRegExpMultiple(isolate,
3703 subject,
3704 regexp,
3705 last_match_info,
3706 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003707 }
3708 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003709 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003710 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3711 return Failure::Exception();
3712}
3713
3714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003715RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003716 NoHandleAllocation ha;
3717 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003718 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003719 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003721 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003722 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003723 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003724 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003725 // Character array used for conversion.
3726 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003727 return isolate->heap()->
3728 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003729 }
3730 }
3731
3732 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003733 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003734 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003735 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003736 }
3737 if (isinf(value)) {
3738 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003739 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003740 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003741 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003742 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003743 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003744 MaybeObject* result =
3745 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003746 DeleteArray(str);
3747 return result;
3748}
3749
3750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003751RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752 NoHandleAllocation ha;
3753 ASSERT(args.length() == 2);
3754
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003755 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003756 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003757 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003758 }
3759 if (isinf(value)) {
3760 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003761 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003762 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003763 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003765 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766 int f = FastD2I(f_number);
3767 RUNTIME_ASSERT(f >= 0);
3768 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003769 MaybeObject* res =
3770 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003771 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003772 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003773}
3774
3775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003776RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777 NoHandleAllocation ha;
3778 ASSERT(args.length() == 2);
3779
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003780 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003781 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003782 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003783 }
3784 if (isinf(value)) {
3785 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003786 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003787 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003788 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003789 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003790 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003791 int f = FastD2I(f_number);
3792 RUNTIME_ASSERT(f >= -1 && f <= 20);
3793 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 MaybeObject* res =
3795 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003796 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003797 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798}
3799
3800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003801RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003802 NoHandleAllocation ha;
3803 ASSERT(args.length() == 2);
3804
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003805 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003806 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003807 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003808 }
3809 if (isinf(value)) {
3810 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003811 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003813 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003814 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003815 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003816 int f = FastD2I(f_number);
3817 RUNTIME_ASSERT(f >= 1 && f <= 21);
3818 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003819 MaybeObject* res =
3820 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003821 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003822 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003823}
3824
3825
3826// Returns a single character string where first character equals
3827// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003828static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003829 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003830 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003831 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003832 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003833 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003834 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003835}
3836
3837
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003838MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3839 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003840 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003841 // Handle [] indexing on Strings
3842 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003843 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3844 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003845 }
3846
3847 // Handle [] indexing on String objects
3848 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003849 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3850 Handle<Object> result =
3851 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3852 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003853 }
3854
3855 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003856 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003857 return prototype->GetElement(index);
3858 }
3859
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003860 return GetElement(object, index);
3861}
3862
3863
lrn@chromium.org303ada72010-10-27 09:33:13 +00003864MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003865 return object->GetElement(index);
3866}
3867
3868
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003869MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3870 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003871 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003872 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003873
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003874 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003875 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003876 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003877 isolate->factory()->NewTypeError("non_object_property_load",
3878 HandleVector(args, 2));
3879 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003880 }
3881
3882 // Check if the given key is an array index.
3883 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003884 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003885 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003886 }
3887
3888 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003889 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003890 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003891 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003892 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003893 bool has_pending_exception = false;
3894 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003895 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003896 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003897 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003898 }
3899
ager@chromium.org32912102009-01-16 10:38:43 +00003900 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003901 // the element if so.
3902 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003903 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003904 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003905 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003906 }
3907}
3908
3909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003910RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003911 NoHandleAllocation ha;
3912 ASSERT(args.length() == 2);
3913
3914 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003915 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003917 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003918}
3919
3920
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003921// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003922RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003923 NoHandleAllocation ha;
3924 ASSERT(args.length() == 2);
3925
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003926 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003927 // itself.
3928 //
3929 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003930 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003931 // global proxy object never has properties. This is the case
3932 // because the global proxy object forwards everything to its hidden
3933 // prototype including local lookups.
3934 //
3935 // Additionally, we need to make sure that we do not cache results
3936 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003937 if (args[0]->IsJSObject() &&
3938 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003939 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003940 args[1]->IsString()) {
3941 JSObject* receiver = JSObject::cast(args[0]);
3942 String* key = String::cast(args[1]);
3943 if (receiver->HasFastProperties()) {
3944 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003945 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003946 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3947 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003948 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003949 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003950 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003951 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003952 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003953 LookupResult result;
3954 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003955 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003956 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003957 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003958 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003959 }
3960 } else {
3961 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003962 StringDictionary* dictionary = receiver->property_dictionary();
3963 int entry = dictionary->FindEntry(key);
3964 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003965 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003966 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003967 if (!receiver->IsGlobalObject()) return value;
3968 value = JSGlobalPropertyCell::cast(value)->value();
3969 if (!value->IsTheHole()) return value;
3970 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003971 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003972 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003973 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3974 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003975 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003976 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003977 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003978 if (index >= 0 && index < str->length()) {
3979 Handle<Object> result = GetCharAt(str, index);
3980 return *result;
3981 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003982 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003983
3984 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003985 return Runtime::GetObjectProperty(isolate,
3986 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003987 args.at<Object>(1));
3988}
3989
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003990// Implements part of 8.12.9 DefineOwnProperty.
3991// There are 3 cases that lead here:
3992// Step 4b - define a new accessor property.
3993// Steps 9c & 12 - replace an existing data property with an accessor property.
3994// Step 12 - update an existing accessor property with an accessor or generic
3995// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003996RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003997 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003998 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003999 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4000 CONVERT_CHECKED(String, name, args[1]);
4001 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004002 Object* fun = args[3];
4003 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004004 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4005 int unchecked = flag_attr->value();
4006 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4007 RUNTIME_ASSERT(!obj->IsNull());
4008 LookupResult result;
4009 obj->LocalLookupRealNamedProperty(name, &result);
4010
4011 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4012 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4013 // delete it to avoid running into trouble in DefineAccessor, which
4014 // handles this incorrectly if the property is readonly (does nothing)
4015 if (result.IsProperty() &&
4016 (result.type() == FIELD || result.type() == NORMAL
4017 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004018 Object* ok;
4019 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004020 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004021 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4022 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004023 }
4024 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4025}
4026
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004027// Implements part of 8.12.9 DefineOwnProperty.
4028// There are 3 cases that lead here:
4029// Step 4a - define a new data property.
4030// Steps 9b & 12 - replace an existing accessor property with a data property.
4031// Step 12 - update an existing data property with a data or generic
4032// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004033RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004034 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004035 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004036 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4037 CONVERT_ARG_CHECKED(String, name, 1);
4038 Handle<Object> obj_value = args.at<Object>(2);
4039
4040 CONVERT_CHECKED(Smi, flag, args[3]);
4041 int unchecked = flag->value();
4042 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4043
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004044 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4045
4046 // Check if this is an element.
4047 uint32_t index;
4048 bool is_element = name->AsArrayIndex(&index);
4049
4050 // Special case for elements if any of the flags are true.
4051 // If elements are in fast case we always implicitly assume that:
4052 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4053 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4054 is_element) {
4055 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004056 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004057 // We do not need to do access checks here since these has already
4058 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004059 Handle<Object> proto(js_object->GetPrototype());
4060 // If proxy is detached, ignore the assignment. Alternatively,
4061 // we could throw an exception.
4062 if (proto->IsNull()) return *obj_value;
4063 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004064 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004065 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004066 // Make sure that we never go back to fast case.
4067 dictionary->set_requires_slow_elements();
4068 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004069 Handle<NumberDictionary> extended_dictionary =
4070 NumberDictionarySet(dictionary, index, obj_value, details);
4071 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004072 if (js_object->GetElementsKind() ==
4073 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
4074 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4075 } else {
4076 js_object->set_elements(*extended_dictionary);
4077 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004078 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004079 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004080 }
4081
ager@chromium.org5c838252010-02-19 08:53:10 +00004082 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004083 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004084
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004085 // To be compatible with safari we do not change the value on API objects
4086 // in defineProperty. Firefox disagrees here, and actually changes the value.
4087 if (result.IsProperty() &&
4088 (result.type() == CALLBACKS) &&
4089 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004090 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004091 }
4092
ager@chromium.org5c838252010-02-19 08:53:10 +00004093 // Take special care when attributes are different and there is already
4094 // a property. For simplicity we normalize the property which enables us
4095 // to not worry about changing the instance_descriptor and creating a new
4096 // map. The current version of SetObjectProperty does not handle attributes
4097 // correctly in the case where a property is a field and is reset with
4098 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004099 if (result.IsProperty() &&
4100 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004101 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004102 if (js_object->IsJSGlobalProxy()) {
4103 // Since the result is a property, the prototype will exist so
4104 // we don't have to check for null.
4105 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004106 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004107 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004108 // Use IgnoreAttributes version since a readonly property may be
4109 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004110 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4111 *obj_value,
4112 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004113 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004114
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004115 return Runtime::ForceSetObjectProperty(isolate,
4116 js_object,
4117 name,
4118 obj_value,
4119 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004120}
4121
4122
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004123// Special case for elements if any of the flags are true.
4124// If elements are in fast case we always implicitly assume that:
4125// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4126static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4127 Handle<JSObject> js_object,
4128 uint32_t index,
4129 Handle<Object> value,
4130 PropertyAttributes attr) {
4131 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004132 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004133 // Make sure that we never go back to fast case.
4134 dictionary->set_requires_slow_elements();
4135 PropertyDetails details = PropertyDetails(attr, NORMAL);
4136 Handle<NumberDictionary> extended_dictionary =
4137 NumberDictionarySet(dictionary, index, value, details);
4138 if (*extended_dictionary != *dictionary) {
4139 js_object->set_elements(*extended_dictionary);
4140 }
4141 return *value;
4142}
4143
4144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004145MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4146 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004147 Handle<Object> key,
4148 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004149 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004150 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004151 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004152
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004153 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004156 isolate->factory()->NewTypeError("non_object_property_store",
4157 HandleVector(args, 2));
4158 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004159 }
4160
4161 // If the object isn't a JavaScript object, we ignore the store.
4162 if (!object->IsJSObject()) return *value;
4163
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004164 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166 // Check if the given key is an array index.
4167 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004168 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4170 // of a string using [] notation. We need to support this too in
4171 // JavaScript.
4172 // In the case of a String object we just need to redirect the assignment to
4173 // the underlying string if the index is in range. Since the underlying
4174 // string does nothing with the assignment then we can ignore such
4175 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004176 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004178 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004179
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004180 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4181 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4182 }
4183
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004184 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004185 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004186 return *value;
4187 }
4188
4189 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004190 Handle<Object> result;
4191 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004192 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4193 return NormalizeObjectSetElement(isolate,
4194 js_object,
4195 index,
4196 value,
4197 attr);
4198 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004199 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004201 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004202 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004203 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004205 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206 return *value;
4207 }
4208
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004210 bool has_pending_exception = false;
4211 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4212 if (has_pending_exception) return Failure::Exception();
4213 Handle<String> name = Handle<String>::cast(converted);
4214
4215 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004216 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004218 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219 }
4220}
4221
4222
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004223MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4224 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004225 Handle<Object> key,
4226 Handle<Object> value,
4227 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004228 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004229
4230 // Check if the given key is an array index.
4231 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004232 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004233 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4234 // of a string using [] notation. We need to support this too in
4235 // JavaScript.
4236 // In the case of a String object we just need to redirect the assignment to
4237 // the underlying string if the index is in range. Since the underlying
4238 // string does nothing with the assignment then we can ignore such
4239 // assignments.
4240 if (js_object->IsStringObjectWithCharacterAt(index)) {
4241 return *value;
4242 }
4243
whesse@chromium.org7b260152011-06-20 15:33:18 +00004244 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004245 }
4246
4247 if (key->IsString()) {
4248 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004249 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004250 } else {
4251 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004252 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004253 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4254 *value,
4255 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004256 }
4257 }
4258
4259 // Call-back into JavaScript to convert the key to a string.
4260 bool has_pending_exception = false;
4261 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4262 if (has_pending_exception) return Failure::Exception();
4263 Handle<String> name = Handle<String>::cast(converted);
4264
4265 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004266 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004267 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004268 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004269 }
4270}
4271
4272
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004273MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004274 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004275 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004276 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004277
4278 // Check if the given key is an array index.
4279 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004280 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004281 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4282 // characters of a string using [] notation. In the case of a
4283 // String object we just need to redirect the deletion to the
4284 // underlying string if the index is in range. Since the
4285 // underlying string does nothing with the deletion, we can ignore
4286 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004287 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004288 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004289 }
4290
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004291 return JSObject::cast(*receiver)->DeleteElement(
4292 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004293 }
4294
4295 Handle<String> key_string;
4296 if (key->IsString()) {
4297 key_string = Handle<String>::cast(key);
4298 } else {
4299 // Call-back into JavaScript to convert the key to a string.
4300 bool has_pending_exception = false;
4301 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4302 if (has_pending_exception) return Failure::Exception();
4303 key_string = Handle<String>::cast(converted);
4304 }
4305
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004306 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004307 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004308}
4309
4310
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004311RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004312 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004313 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004314
4315 Handle<Object> object = args.at<Object>(0);
4316 Handle<Object> key = args.at<Object>(1);
4317 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004318 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004319 RUNTIME_ASSERT(
4320 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004321 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004322 PropertyAttributes attributes =
4323 static_cast<PropertyAttributes>(unchecked_attributes);
4324
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004325 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004326 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004327 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004328 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4329 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004330 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004331 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004332
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004333 return Runtime::SetObjectProperty(isolate,
4334 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004335 key,
4336 value,
4337 attributes,
4338 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004339}
4340
4341
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004342// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004343// This is used to decide if we should transform null and undefined
4344// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004345RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004346 NoHandleAllocation ha;
4347 RUNTIME_ASSERT(args.length() == 1);
4348
4349 Handle<Object> object = args.at<Object>(0);
4350
4351 if (object->IsJSFunction()) {
4352 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004353 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004354 }
4355 return isolate->heap()->undefined_value();
4356}
4357
4358
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004359// Set a local property, even if it is READ_ONLY. If the property does not
4360// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004361RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004362 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004363 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004364 CONVERT_CHECKED(JSObject, object, args[0]);
4365 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004366 // Compute attributes.
4367 PropertyAttributes attributes = NONE;
4368 if (args.length() == 4) {
4369 CONVERT_CHECKED(Smi, value_obj, args[3]);
4370 int unchecked_value = value_obj->value();
4371 // Only attribute bits should be set.
4372 RUNTIME_ASSERT(
4373 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4374 attributes = static_cast<PropertyAttributes>(unchecked_value);
4375 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004376
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004377 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004378 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004379}
4380
4381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004382RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004383 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004384 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004385
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004386 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004387 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004388 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004389 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004390 ? JSReceiver::STRICT_DELETION
4391 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004392}
4393
4394
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004395static Object* HasLocalPropertyImplementation(Isolate* isolate,
4396 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004397 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004398 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004399 // Handle hidden prototypes. If there's a hidden prototype above this thing
4400 // then we have to check it for properties, because they are supposed to
4401 // look like they are on this object.
4402 Handle<Object> proto(object->GetPrototype());
4403 if (proto->IsJSObject() &&
4404 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004405 return HasLocalPropertyImplementation(isolate,
4406 Handle<JSObject>::cast(proto),
4407 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004408 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004409 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004410}
4411
4412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004413RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004414 NoHandleAllocation ha;
4415 ASSERT(args.length() == 2);
4416 CONVERT_CHECKED(String, key, args[1]);
4417
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004418 uint32_t index;
4419 const bool key_is_array_index = key->AsArrayIndex(&index);
4420
ager@chromium.org9085a012009-05-11 19:22:57 +00004421 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004423 if (obj->IsJSObject()) {
4424 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004425 // Fast case: either the key is a real named property or it is not
4426 // an array index and there are no interceptors or hidden
4427 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004428 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004429 Map* map = object->map();
4430 if (!key_is_array_index &&
4431 !map->has_named_interceptor() &&
4432 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4433 return isolate->heap()->false_value();
4434 }
4435 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004436 HandleScope scope(isolate);
4437 return HasLocalPropertyImplementation(isolate,
4438 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004439 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004440 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004441 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004442 String* string = String::cast(obj);
4443 if (index < static_cast<uint32_t>(string->length())) {
4444 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004445 }
4446 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004447 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004448}
4449
4450
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004451RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004452 NoHandleAllocation na;
4453 ASSERT(args.length() == 2);
4454
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004455 // Only JS receivers can have properties.
4456 if (args[0]->IsJSReceiver()) {
4457 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004458 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004459 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004460 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004461 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004462}
4463
4464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004465RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004466 NoHandleAllocation na;
4467 ASSERT(args.length() == 2);
4468
4469 // Only JS objects can have elements.
4470 if (args[0]->IsJSObject()) {
4471 JSObject* object = JSObject::cast(args[0]);
4472 CONVERT_CHECKED(Smi, index_obj, args[1]);
4473 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004474 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004475 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004476 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477}
4478
4479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004480RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 NoHandleAllocation ha;
4482 ASSERT(args.length() == 2);
4483
4484 CONVERT_CHECKED(JSObject, object, args[0]);
4485 CONVERT_CHECKED(String, key, args[1]);
4486
4487 uint32_t index;
4488 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004489 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 }
4491
ager@chromium.org870a0b62008-11-04 11:43:05 +00004492 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004493 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004494}
4495
4496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004497RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004498 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004500 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004501 return *GetKeysFor(object);
4502}
4503
4504
4505// Returns either a FixedArray as Runtime_GetPropertyNames,
4506// or, if the given object has an enum cache that contains
4507// all enumerable properties of the object and its prototypes
4508// have none, the map of the object. This is used to speed up
4509// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004510RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004511 ASSERT(args.length() == 1);
4512
4513 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4514
4515 if (raw_object->IsSimpleEnum()) return raw_object->map();
4516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004517 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004518 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004519 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4520 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521
4522 // Test again, since cache may have been built by preceding call.
4523 if (object->IsSimpleEnum()) return object->map();
4524
4525 return *content;
4526}
4527
4528
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004529// Find the length of the prototype chain that is to to handled as one. If a
4530// prototype object is hidden it is to be viewed as part of the the object it
4531// is prototype for.
4532static int LocalPrototypeChainLength(JSObject* obj) {
4533 int count = 1;
4534 Object* proto = obj->GetPrototype();
4535 while (proto->IsJSObject() &&
4536 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4537 count++;
4538 proto = JSObject::cast(proto)->GetPrototype();
4539 }
4540 return count;
4541}
4542
4543
4544// Return the names of the local named properties.
4545// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004546RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004547 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004548 ASSERT(args.length() == 1);
4549 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004550 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004551 }
4552 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4553
4554 // Skip the global proxy as it has no properties and always delegates to the
4555 // real global object.
4556 if (obj->IsJSGlobalProxy()) {
4557 // Only collect names if access is permitted.
4558 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004559 !isolate->MayNamedAccess(*obj,
4560 isolate->heap()->undefined_value(),
4561 v8::ACCESS_KEYS)) {
4562 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4563 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004564 }
4565 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4566 }
4567
4568 // Find the number of objects making up this.
4569 int length = LocalPrototypeChainLength(*obj);
4570
4571 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004572 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004573 int total_property_count = 0;
4574 Handle<JSObject> jsproto = obj;
4575 for (int i = 0; i < length; i++) {
4576 // Only collect names if access is permitted.
4577 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 !isolate->MayNamedAccess(*jsproto,
4579 isolate->heap()->undefined_value(),
4580 v8::ACCESS_KEYS)) {
4581 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4582 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004583 }
4584 int n;
4585 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4586 local_property_count[i] = n;
4587 total_property_count += n;
4588 if (i < length - 1) {
4589 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4590 }
4591 }
4592
4593 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004594 Handle<FixedArray> names =
4595 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004596
4597 // Get the property names.
4598 jsproto = obj;
4599 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004600 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004601 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004602 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4603 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004604 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004605 proto_with_hidden_properties++;
4606 }
4607 if (i < length - 1) {
4608 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4609 }
4610 }
4611
4612 // Filter out name of hidden propeties object.
4613 if (proto_with_hidden_properties > 0) {
4614 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004615 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004616 names->length() - proto_with_hidden_properties);
4617 int dest_pos = 0;
4618 for (int i = 0; i < total_property_count; i++) {
4619 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004621 continue;
4622 }
4623 names->set(dest_pos++, name);
4624 }
4625 }
4626
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004627 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004628}
4629
4630
4631// Return the names of the local indexed properties.
4632// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004633RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004634 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004635 ASSERT(args.length() == 1);
4636 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004637 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004638 }
4639 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4640
4641 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004642 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004643 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004644 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004645}
4646
4647
4648// Return information on whether an object has a named or indexed interceptor.
4649// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004650RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004651 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004652 ASSERT(args.length() == 1);
4653 if (!args[0]->IsJSObject()) {
4654 return Smi::FromInt(0);
4655 }
4656 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4657
4658 int result = 0;
4659 if (obj->HasNamedInterceptor()) result |= 2;
4660 if (obj->HasIndexedInterceptor()) result |= 1;
4661
4662 return Smi::FromInt(result);
4663}
4664
4665
4666// Return property names from named interceptor.
4667// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004668RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004669 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004670 ASSERT(args.length() == 1);
4671 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4672
4673 if (obj->HasNamedInterceptor()) {
4674 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4675 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4676 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004677 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004678}
4679
4680
4681// Return element names from indexed interceptor.
4682// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004683RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004684 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004685 ASSERT(args.length() == 1);
4686 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4687
4688 if (obj->HasIndexedInterceptor()) {
4689 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4690 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4691 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004692 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004693}
4694
4695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004696RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004697 ASSERT_EQ(args.length(), 1);
4698 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004699 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004700 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004701
4702 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004703 // Do access checks before going to the global object.
4704 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004705 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004706 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004707 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4708 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004709 }
4710
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004711 Handle<Object> proto(object->GetPrototype());
4712 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004713 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004714 object = Handle<JSObject>::cast(proto);
4715 }
4716
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004717 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4718 LOCAL_ONLY);
4719 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4720 // property array and since the result is mutable we have to create
4721 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004722 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004723 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004724 for (int i = 0; i < length; i++) {
4725 Object* entry = contents->get(i);
4726 if (entry->IsString()) {
4727 copy->set(i, entry);
4728 } else {
4729 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004730 HandleScope scope(isolate);
4731 Handle<Object> entry_handle(entry, isolate);
4732 Handle<Object> entry_str =
4733 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004734 copy->set(i, *entry_str);
4735 }
4736 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004737 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004738}
4739
4740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004741RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742 NoHandleAllocation ha;
4743 ASSERT(args.length() == 1);
4744
4745 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004746 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747 it.AdvanceToArgumentsFrame();
4748 JavaScriptFrame* frame = it.frame();
4749
4750 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004751 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004752
4753 // Try to convert the key to an index. If successful and within
4754 // index return the the argument from the frame.
4755 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004756 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757 return frame->GetParameter(index);
4758 }
4759
4760 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004761 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 bool exception = false;
4763 Handle<Object> converted =
4764 Execution::ToString(args.at<Object>(0), &exception);
4765 if (exception) return Failure::Exception();
4766 Handle<String> key = Handle<String>::cast(converted);
4767
4768 // Try to convert the string key into an array index.
4769 if (key->AsArrayIndex(&index)) {
4770 if (index < n) {
4771 return frame->GetParameter(index);
4772 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004773 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774 }
4775 }
4776
4777 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4779 if (key->Equals(isolate->heap()->callee_symbol())) {
4780 Object* function = frame->function();
4781 if (function->IsJSFunction() &&
4782 JSFunction::cast(function)->shared()->strict_mode()) {
4783 return isolate->Throw(*isolate->factory()->NewTypeError(
4784 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4785 }
4786 return function;
4787 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004788
4789 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004790 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791}
4792
4793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004794RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004795 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004796
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004797 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004798 Handle<Object> object = args.at<Object>(0);
4799 if (object->IsJSObject()) {
4800 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004801 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004802 MaybeObject* ok = js_object->TransformToFastProperties(0);
4803 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004804 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004805 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004806 return *object;
4807}
4808
4809
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004810RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004811 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004812
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004813 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004814 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004815 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004816 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004817 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004818 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004819 return *object;
4820}
4821
4822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004823RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824 NoHandleAllocation ha;
4825 ASSERT(args.length() == 1);
4826
4827 return args[0]->ToBoolean();
4828}
4829
4830
4831// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4832// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004833RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004834 NoHandleAllocation ha;
4835
4836 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004837 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004838 HeapObject* heap_obj = HeapObject::cast(obj);
4839
4840 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004841 if (heap_obj->map()->is_undetectable()) {
4842 return isolate->heap()->undefined_symbol();
4843 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004844
4845 InstanceType instance_type = heap_obj->map()->instance_type();
4846 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004847 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848 }
4849
4850 switch (instance_type) {
4851 case ODDBALL_TYPE:
4852 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004853 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004854 }
4855 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004856 return FLAG_harmony_typeof
4857 ? isolate->heap()->null_symbol()
4858 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004859 }
4860 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004861 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004862 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004863 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004864 default:
4865 // For any kind of object not handled above, the spec rule for
4866 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004867 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004868 }
4869}
4870
4871
lrn@chromium.org25156de2010-04-06 13:10:27 +00004872static bool AreDigits(const char*s, int from, int to) {
4873 for (int i = from; i < to; i++) {
4874 if (s[i] < '0' || s[i] > '9') return false;
4875 }
4876
4877 return true;
4878}
4879
4880
4881static int ParseDecimalInteger(const char*s, int from, int to) {
4882 ASSERT(to - from < 10); // Overflow is not possible.
4883 ASSERT(from < to);
4884 int d = s[from] - '0';
4885
4886 for (int i = from + 1; i < to; i++) {
4887 d = 10 * d + (s[i] - '0');
4888 }
4889
4890 return d;
4891}
4892
4893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004894RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004895 NoHandleAllocation ha;
4896 ASSERT(args.length() == 1);
4897 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004898 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004899
4900 // Fast case: short integer or some sorts of junk values.
4901 int len = subject->length();
4902 if (subject->IsSeqAsciiString()) {
4903 if (len == 0) return Smi::FromInt(0);
4904
4905 char const* data = SeqAsciiString::cast(subject)->GetChars();
4906 bool minus = (data[0] == '-');
4907 int start_pos = (minus ? 1 : 0);
4908
4909 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004910 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004911 } else if (data[start_pos] > '9') {
4912 // Fast check for a junk value. A valid string may start from a
4913 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4914 // the 'I' character ('Infinity'). All of that have codes not greater than
4915 // '9' except 'I'.
4916 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004917 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004918 }
4919 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4920 // The maximal/minimal smi has 10 digits. If the string has less digits we
4921 // know it will fit into the smi-data type.
4922 int d = ParseDecimalInteger(data, start_pos, len);
4923 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004924 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004925 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004926 } else if (!subject->HasHashCode() &&
4927 len <= String::kMaxArrayIndexSize &&
4928 (len == 1 || data[0] != '0')) {
4929 // String hash is not calculated yet but all the data are present.
4930 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004931 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004932#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004933 subject->Hash(); // Force hash calculation.
4934 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4935 static_cast<int>(hash));
4936#endif
4937 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004938 }
4939 return Smi::FromInt(d);
4940 }
4941 }
4942
4943 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004944 return isolate->heap()->NumberFromDouble(
4945 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004946}
4947
4948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004949RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004950 NoHandleAllocation ha;
4951 ASSERT(args.length() == 1);
4952
4953 CONVERT_CHECKED(JSArray, codes, args[0]);
4954 int length = Smi::cast(codes->length())->value();
4955
4956 // Check if the string can be ASCII.
4957 int i;
4958 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004959 Object* element;
4960 { MaybeObject* maybe_element = codes->GetElement(i);
4961 // We probably can't get an exception here, but just in order to enforce
4962 // the checking of inputs in the runtime calls we check here.
4963 if (!maybe_element->ToObject(&element)) return maybe_element;
4964 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004965 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4966 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4967 break;
4968 }
4969
lrn@chromium.org303ada72010-10-27 09:33:13 +00004970 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004971 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004972 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004973 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004974 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004975 }
4976
lrn@chromium.org303ada72010-10-27 09:33:13 +00004977 Object* object = NULL;
4978 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004979 String* result = String::cast(object);
4980 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004981 Object* element;
4982 { MaybeObject* maybe_element = codes->GetElement(i);
4983 if (!maybe_element->ToObject(&element)) return maybe_element;
4984 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004985 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004986 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004987 }
4988 return result;
4989}
4990
4991
4992// kNotEscaped is generated by the following:
4993//
4994// #!/bin/perl
4995// for (my $i = 0; $i < 256; $i++) {
4996// print "\n" if $i % 16 == 0;
4997// my $c = chr($i);
4998// my $escaped = 1;
4999// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5000// print $escaped ? "0, " : "1, ";
5001// }
5002
5003
5004static bool IsNotEscaped(uint16_t character) {
5005 // Only for 8 bit characters, the rest are always escaped (in a different way)
5006 ASSERT(character < 256);
5007 static const char kNotEscaped[256] = {
5008 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5009 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5010 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5011 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5012 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5013 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5014 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5015 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5016 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5017 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5018 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5019 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5020 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5021 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5022 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5023 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5024 };
5025 return kNotEscaped[character] != 0;
5026}
5027
5028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005029RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005030 const char hex_chars[] = "0123456789ABCDEF";
5031 NoHandleAllocation ha;
5032 ASSERT(args.length() == 1);
5033 CONVERT_CHECKED(String, source, args[0]);
5034
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005035 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005036
5037 int escaped_length = 0;
5038 int length = source->length();
5039 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005040 Access<StringInputBuffer> buffer(
5041 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005042 buffer->Reset(source);
5043 while (buffer->has_more()) {
5044 uint16_t character = buffer->GetNext();
5045 if (character >= 256) {
5046 escaped_length += 6;
5047 } else if (IsNotEscaped(character)) {
5048 escaped_length++;
5049 } else {
5050 escaped_length += 3;
5051 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005052 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005053 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005054 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005055 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005056 return Failure::OutOfMemoryException();
5057 }
5058 }
5059 }
5060 // No length change implies no change. Return original string if no change.
5061 if (escaped_length == length) {
5062 return source;
5063 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005064 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005065 { MaybeObject* maybe_o =
5066 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005067 if (!maybe_o->ToObject(&o)) return maybe_o;
5068 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005069 String* destination = String::cast(o);
5070 int dest_position = 0;
5071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072 Access<StringInputBuffer> buffer(
5073 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005074 buffer->Rewind();
5075 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005076 uint16_t chr = buffer->GetNext();
5077 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005078 destination->Set(dest_position, '%');
5079 destination->Set(dest_position+1, 'u');
5080 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5081 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5082 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5083 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005084 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005085 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005086 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005087 dest_position++;
5088 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005089 destination->Set(dest_position, '%');
5090 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5091 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005092 dest_position += 3;
5093 }
5094 }
5095 return destination;
5096}
5097
5098
5099static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5100 static const signed char kHexValue['g'] = {
5101 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5102 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5103 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5104 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5105 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5106 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5107 -1, 10, 11, 12, 13, 14, 15 };
5108
5109 if (character1 > 'f') return -1;
5110 int hi = kHexValue[character1];
5111 if (hi == -1) return -1;
5112 if (character2 > 'f') return -1;
5113 int lo = kHexValue[character2];
5114 if (lo == -1) return -1;
5115 return (hi << 4) + lo;
5116}
5117
5118
ager@chromium.org870a0b62008-11-04 11:43:05 +00005119static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005120 int i,
5121 int length,
5122 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005123 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005124 int32_t hi = 0;
5125 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005126 if (character == '%' &&
5127 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005128 source->Get(i + 1) == 'u' &&
5129 (hi = TwoDigitHex(source->Get(i + 2),
5130 source->Get(i + 3))) != -1 &&
5131 (lo = TwoDigitHex(source->Get(i + 4),
5132 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005133 *step = 6;
5134 return (hi << 8) + lo;
5135 } else if (character == '%' &&
5136 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005137 (lo = TwoDigitHex(source->Get(i + 1),
5138 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005139 *step = 3;
5140 return lo;
5141 } else {
5142 *step = 1;
5143 return character;
5144 }
5145}
5146
5147
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005148RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005149 NoHandleAllocation ha;
5150 ASSERT(args.length() == 1);
5151 CONVERT_CHECKED(String, source, args[0]);
5152
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005153 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005154
5155 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005156 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005157
5158 int unescaped_length = 0;
5159 for (int i = 0; i < length; unescaped_length++) {
5160 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005161 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005162 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005163 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005164 i += step;
5165 }
5166
5167 // No length change implies no change. Return original string if no change.
5168 if (unescaped_length == length)
5169 return source;
5170
lrn@chromium.org303ada72010-10-27 09:33:13 +00005171 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005172 { MaybeObject* maybe_o =
5173 ascii ?
5174 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5175 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005176 if (!maybe_o->ToObject(&o)) return maybe_o;
5177 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005178 String* destination = String::cast(o);
5179
5180 int dest_position = 0;
5181 for (int i = 0; i < length; dest_position++) {
5182 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005183 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005184 i += step;
5185 }
5186 return destination;
5187}
5188
5189
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005190static const unsigned int kQuoteTableLength = 128u;
5191
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005192static const int kJsonQuotesCharactersPerEntry = 8;
5193static const char* const JsonQuotes =
5194 "\\u0000 \\u0001 \\u0002 \\u0003 "
5195 "\\u0004 \\u0005 \\u0006 \\u0007 "
5196 "\\b \\t \\n \\u000b "
5197 "\\f \\r \\u000e \\u000f "
5198 "\\u0010 \\u0011 \\u0012 \\u0013 "
5199 "\\u0014 \\u0015 \\u0016 \\u0017 "
5200 "\\u0018 \\u0019 \\u001a \\u001b "
5201 "\\u001c \\u001d \\u001e \\u001f "
5202 " ! \\\" # "
5203 "$ % & ' "
5204 "( ) * + "
5205 ", - . / "
5206 "0 1 2 3 "
5207 "4 5 6 7 "
5208 "8 9 : ; "
5209 "< = > ? "
5210 "@ A B C "
5211 "D E F G "
5212 "H I J K "
5213 "L M N O "
5214 "P Q R S "
5215 "T U V W "
5216 "X Y Z [ "
5217 "\\\\ ] ^ _ "
5218 "` a b c "
5219 "d e f g "
5220 "h i j k "
5221 "l m n o "
5222 "p q r s "
5223 "t u v w "
5224 "x y z { "
5225 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005226
5227
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005228// For a string that is less than 32k characters it should always be
5229// possible to allocate it in new space.
5230static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5231
5232
5233// Doing JSON quoting cannot make the string more than this many times larger.
5234static const int kJsonQuoteWorstCaseBlowup = 6;
5235
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005236static const int kSpaceForQuotesAndComma = 3;
5237static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005238
5239// Covers the entire ASCII range (all other characters are unchanged by JSON
5240// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005241static const byte JsonQuoteLengths[kQuoteTableLength] = {
5242 6, 6, 6, 6, 6, 6, 6, 6,
5243 2, 2, 2, 6, 2, 2, 6, 6,
5244 6, 6, 6, 6, 6, 6, 6, 6,
5245 6, 6, 6, 6, 6, 6, 6, 6,
5246 1, 1, 2, 1, 1, 1, 1, 1,
5247 1, 1, 1, 1, 1, 1, 1, 1,
5248 1, 1, 1, 1, 1, 1, 1, 1,
5249 1, 1, 1, 1, 1, 1, 1, 1,
5250 1, 1, 1, 1, 1, 1, 1, 1,
5251 1, 1, 1, 1, 1, 1, 1, 1,
5252 1, 1, 1, 1, 1, 1, 1, 1,
5253 1, 1, 1, 1, 2, 1, 1, 1,
5254 1, 1, 1, 1, 1, 1, 1, 1,
5255 1, 1, 1, 1, 1, 1, 1, 1,
5256 1, 1, 1, 1, 1, 1, 1, 1,
5257 1, 1, 1, 1, 1, 1, 1, 1,
5258};
5259
5260
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005261template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005262MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005263
5264
5265template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005266MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5267 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005268}
5269
5270
5271template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005272MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5273 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005274}
5275
5276
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005277template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005278static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5279 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005280 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005281 const Char* read_cursor = characters.start();
5282 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005283 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005284 int quoted_length = kSpaceForQuotes;
5285 while (read_cursor < end) {
5286 Char c = *(read_cursor++);
5287 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5288 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005289 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005290 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005291 }
5292 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005293 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5294 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005295 Object* new_object;
5296 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005297 return new_alloc;
5298 }
5299 StringType* new_string = StringType::cast(new_object);
5300
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005301 Char* write_cursor = reinterpret_cast<Char*>(
5302 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005303 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005304 *(write_cursor++) = '"';
5305
5306 read_cursor = characters.start();
5307 while (read_cursor < end) {
5308 Char c = *(read_cursor++);
5309 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5310 *(write_cursor++) = c;
5311 } else {
5312 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5313 const char* replacement = JsonQuotes +
5314 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5315 for (int i = 0; i < len; i++) {
5316 *write_cursor++ = *replacement++;
5317 }
5318 }
5319 }
5320 *(write_cursor++) = '"';
5321 return new_string;
5322}
5323
5324
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005325template <typename SinkChar, typename SourceChar>
5326static inline SinkChar* WriteQuoteJsonString(
5327 Isolate* isolate,
5328 SinkChar* write_cursor,
5329 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005330 // SinkChar is only char if SourceChar is guaranteed to be char.
5331 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005332 const SourceChar* read_cursor = characters.start();
5333 const SourceChar* end = read_cursor + characters.length();
5334 *(write_cursor++) = '"';
5335 while (read_cursor < end) {
5336 SourceChar c = *(read_cursor++);
5337 if (sizeof(SourceChar) > 1u &&
5338 static_cast<unsigned>(c) >= kQuoteTableLength) {
5339 *(write_cursor++) = static_cast<SinkChar>(c);
5340 } else {
5341 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5342 const char* replacement = JsonQuotes +
5343 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5344 write_cursor[0] = replacement[0];
5345 if (len > 1) {
5346 write_cursor[1] = replacement[1];
5347 if (len > 2) {
5348 ASSERT(len == 6);
5349 write_cursor[2] = replacement[2];
5350 write_cursor[3] = replacement[3];
5351 write_cursor[4] = replacement[4];
5352 write_cursor[5] = replacement[5];
5353 }
5354 }
5355 write_cursor += len;
5356 }
5357 }
5358 *(write_cursor++) = '"';
5359 return write_cursor;
5360}
5361
5362
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005363template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005364static MaybeObject* QuoteJsonString(Isolate* isolate,
5365 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005366 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005367 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005368 int worst_case_length =
5369 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005370 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005371 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005372 }
5373
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005374 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5375 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005376 Object* new_object;
5377 if (!new_alloc->ToObject(&new_object)) {
5378 return new_alloc;
5379 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005380 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005381 // Even if our string is small enough to fit in new space we still have to
5382 // handle it being allocated in old space as may happen in the third
5383 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5384 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005385 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005386 }
5387 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005388 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005389
5390 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5391 Char* write_cursor = reinterpret_cast<Char*>(
5392 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005393 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005394 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5395 write_cursor,
5396 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005397 int final_length = static_cast<int>(
5398 write_cursor - reinterpret_cast<Char*>(
5399 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005400 isolate->heap()->new_space()->
5401 template ShrinkStringAtAllocationBoundary<StringType>(
5402 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005403 return new_string;
5404}
5405
5406
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005407RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005408 NoHandleAllocation ha;
5409 CONVERT_CHECKED(String, str, args[0]);
5410 if (!str->IsFlat()) {
5411 MaybeObject* try_flatten = str->TryFlatten();
5412 Object* flat;
5413 if (!try_flatten->ToObject(&flat)) {
5414 return try_flatten;
5415 }
5416 str = String::cast(flat);
5417 ASSERT(str->IsFlat());
5418 }
5419 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005420 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5421 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005422 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005423 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5424 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005425 }
5426}
5427
5428
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005429RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005430 NoHandleAllocation ha;
5431 CONVERT_CHECKED(String, str, args[0]);
5432 if (!str->IsFlat()) {
5433 MaybeObject* try_flatten = str->TryFlatten();
5434 Object* flat;
5435 if (!try_flatten->ToObject(&flat)) {
5436 return try_flatten;
5437 }
5438 str = String::cast(flat);
5439 ASSERT(str->IsFlat());
5440 }
5441 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005442 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5443 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005444 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005445 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5446 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005447 }
5448}
5449
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005450
5451template <typename Char, typename StringType>
5452static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5453 FixedArray* array,
5454 int worst_case_length) {
5455 int length = array->length();
5456
5457 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5458 worst_case_length);
5459 Object* new_object;
5460 if (!new_alloc->ToObject(&new_object)) {
5461 return new_alloc;
5462 }
5463 if (!isolate->heap()->new_space()->Contains(new_object)) {
5464 // Even if our string is small enough to fit in new space we still have to
5465 // handle it being allocated in old space as may happen in the third
5466 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5467 // CEntryStub::GenerateCore.
5468 return isolate->heap()->undefined_value();
5469 }
5470 AssertNoAllocation no_gc;
5471 StringType* new_string = StringType::cast(new_object);
5472 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5473
5474 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5475 Char* write_cursor = reinterpret_cast<Char*>(
5476 new_string->address() + SeqAsciiString::kHeaderSize);
5477 *(write_cursor++) = '[';
5478 for (int i = 0; i < length; i++) {
5479 if (i != 0) *(write_cursor++) = ',';
5480 String* str = String::cast(array->get(i));
5481 if (str->IsTwoByteRepresentation()) {
5482 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5483 write_cursor,
5484 str->ToUC16Vector());
5485 } else {
5486 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5487 write_cursor,
5488 str->ToAsciiVector());
5489 }
5490 }
5491 *(write_cursor++) = ']';
5492
5493 int final_length = static_cast<int>(
5494 write_cursor - reinterpret_cast<Char*>(
5495 new_string->address() + SeqAsciiString::kHeaderSize));
5496 isolate->heap()->new_space()->
5497 template ShrinkStringAtAllocationBoundary<StringType>(
5498 new_string, final_length);
5499 return new_string;
5500}
5501
5502
5503RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5504 NoHandleAllocation ha;
5505 ASSERT(args.length() == 1);
5506 CONVERT_CHECKED(JSArray, array, args[0]);
5507
5508 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5509 FixedArray* elements = FixedArray::cast(array->elements());
5510 int n = elements->length();
5511 bool ascii = true;
5512 int total_length = 0;
5513
5514 for (int i = 0; i < n; i++) {
5515 Object* elt = elements->get(i);
5516 if (!elt->IsString()) return isolate->heap()->undefined_value();
5517 String* element = String::cast(elt);
5518 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5519 total_length += element->length();
5520 if (ascii && element->IsTwoByteRepresentation()) {
5521 ascii = false;
5522 }
5523 }
5524
5525 int worst_case_length =
5526 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5527 + total_length * kJsonQuoteWorstCaseBlowup;
5528
5529 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5530 return isolate->heap()->undefined_value();
5531 }
5532
5533 if (ascii) {
5534 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5535 elements,
5536 worst_case_length);
5537 } else {
5538 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5539 elements,
5540 worst_case_length);
5541 }
5542}
5543
5544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005545RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005546 NoHandleAllocation ha;
5547
5548 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005549 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005550
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005551 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005552
lrn@chromium.org25156de2010-04-06 13:10:27 +00005553 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005554 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005555 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005556}
5557
5558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005559RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005560 NoHandleAllocation ha;
5561 CONVERT_CHECKED(String, str, args[0]);
5562
5563 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005564 double value = StringToDouble(isolate->unicode_cache(),
5565 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005566
5567 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005568 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005569}
5570
5571
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005572template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005573MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005574 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005575 String* s,
5576 int length,
5577 int input_string_length,
5578 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005579 // We try this twice, once with the assumption that the result is no longer
5580 // than the input and, if that assumption breaks, again with the exact
5581 // length. This may not be pretty, but it is nicer than what was here before
5582 // and I hereby claim my vaffel-is.
5583 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005584 // Allocate the resulting string.
5585 //
5586 // NOTE: This assumes that the upper/lower case of an ascii
5587 // character is also ascii. This is currently the case, but it
5588 // might break in the future if we implement more context and locale
5589 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005590 Object* o;
5591 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005592 ? isolate->heap()->AllocateRawAsciiString(length)
5593 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005594 if (!maybe_o->ToObject(&o)) return maybe_o;
5595 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005596 String* result = String::cast(o);
5597 bool has_changed_character = false;
5598
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005599 // Convert all characters to upper case, assuming that they will fit
5600 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005601 Access<StringInputBuffer> buffer(
5602 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005603 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005604 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005605 // We can assume that the string is not empty
5606 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005607 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005608 bool has_next = buffer->has_more();
5609 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005610 int char_length = mapping->get(current, next, chars);
5611 if (char_length == 0) {
5612 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005613 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005614 i++;
5615 } else if (char_length == 1) {
5616 // Common case: converting the letter resulted in one character.
5617 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005618 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005619 has_changed_character = true;
5620 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005621 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005622 // We've assumed that the result would be as long as the
5623 // input but here is a character that converts to several
5624 // characters. No matter, we calculate the exact length
5625 // of the result and try the whole thing again.
5626 //
5627 // Note that this leaves room for optimization. We could just
5628 // memcpy what we already have to the result string. Also,
5629 // the result string is the last object allocated we could
5630 // "realloc" it and probably, in the vast majority of cases,
5631 // extend the existing string to be able to hold the full
5632 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005633 int next_length = 0;
5634 if (has_next) {
5635 next_length = mapping->get(next, 0, chars);
5636 if (next_length == 0) next_length = 1;
5637 }
5638 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005639 while (buffer->has_more()) {
5640 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005641 // NOTE: we use 0 as the next character here because, while
5642 // the next character may affect what a character converts to,
5643 // it does not in any case affect the length of what it convert
5644 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005645 int char_length = mapping->get(current, 0, chars);
5646 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005647 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005648 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005649 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005650 return Failure::OutOfMemoryException();
5651 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005652 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005653 // Try again with the real length.
5654 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005655 } else {
5656 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005657 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005658 i++;
5659 }
5660 has_changed_character = true;
5661 }
5662 current = next;
5663 }
5664 if (has_changed_character) {
5665 return result;
5666 } else {
5667 // If we didn't actually change anything in doing the conversion
5668 // we simple return the result and let the converted string
5669 // become garbage; there is no reason to keep two identical strings
5670 // alive.
5671 return s;
5672 }
5673}
5674
5675
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005676namespace {
5677
lrn@chromium.org303ada72010-10-27 09:33:13 +00005678static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5679
5680
5681// Given a word and two range boundaries returns a word with high bit
5682// set in every byte iff the corresponding input byte was strictly in
5683// the range (m, n). All the other bits in the result are cleared.
5684// This function is only useful when it can be inlined and the
5685// boundaries are statically known.
5686// Requires: all bytes in the input word and the boundaries must be
5687// ascii (less than 0x7F).
5688static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5689 // Every byte in an ascii string is less than or equal to 0x7F.
5690 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5691 // Use strict inequalities since in edge cases the function could be
5692 // further simplified.
5693 ASSERT(0 < m && m < n && n < 0x7F);
5694 // Has high bit set in every w byte less than n.
5695 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5696 // Has high bit set in every w byte greater than m.
5697 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5698 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5699}
5700
5701
5702enum AsciiCaseConversion {
5703 ASCII_TO_LOWER,
5704 ASCII_TO_UPPER
5705};
5706
5707
5708template <AsciiCaseConversion dir>
5709struct FastAsciiConverter {
5710 static bool Convert(char* dst, char* src, int length) {
5711#ifdef DEBUG
5712 char* saved_dst = dst;
5713 char* saved_src = src;
5714#endif
5715 // We rely on the distance between upper and lower case letters
5716 // being a known power of 2.
5717 ASSERT('a' - 'A' == (1 << 5));
5718 // Boundaries for the range of input characters than require conversion.
5719 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5720 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5721 bool changed = false;
5722 char* const limit = src + length;
5723#ifdef V8_HOST_CAN_READ_UNALIGNED
5724 // Process the prefix of the input that requires no conversion one
5725 // (machine) word at a time.
5726 while (src <= limit - sizeof(uintptr_t)) {
5727 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5728 if (AsciiRangeMask(w, lo, hi) != 0) {
5729 changed = true;
5730 break;
5731 }
5732 *reinterpret_cast<uintptr_t*>(dst) = w;
5733 src += sizeof(uintptr_t);
5734 dst += sizeof(uintptr_t);
5735 }
5736 // Process the remainder of the input performing conversion when
5737 // required one word at a time.
5738 while (src <= limit - sizeof(uintptr_t)) {
5739 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5740 uintptr_t m = AsciiRangeMask(w, lo, hi);
5741 // The mask has high (7th) bit set in every byte that needs
5742 // conversion and we know that the distance between cases is
5743 // 1 << 5.
5744 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5745 src += sizeof(uintptr_t);
5746 dst += sizeof(uintptr_t);
5747 }
5748#endif
5749 // Process the last few bytes of the input (or the whole input if
5750 // unaligned access is not supported).
5751 while (src < limit) {
5752 char c = *src;
5753 if (lo < c && c < hi) {
5754 c ^= (1 << 5);
5755 changed = true;
5756 }
5757 *dst = c;
5758 ++src;
5759 ++dst;
5760 }
5761#ifdef DEBUG
5762 CheckConvert(saved_dst, saved_src, length, changed);
5763#endif
5764 return changed;
5765 }
5766
5767#ifdef DEBUG
5768 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5769 bool expected_changed = false;
5770 for (int i = 0; i < length; i++) {
5771 if (dst[i] == src[i]) continue;
5772 expected_changed = true;
5773 if (dir == ASCII_TO_LOWER) {
5774 ASSERT('A' <= src[i] && src[i] <= 'Z');
5775 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5776 } else {
5777 ASSERT(dir == ASCII_TO_UPPER);
5778 ASSERT('a' <= src[i] && src[i] <= 'z');
5779 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5780 }
5781 }
5782 ASSERT(expected_changed == changed);
5783 }
5784#endif
5785};
5786
5787
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005788struct ToLowerTraits {
5789 typedef unibrow::ToLowercase UnibrowConverter;
5790
lrn@chromium.org303ada72010-10-27 09:33:13 +00005791 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005792};
5793
5794
5795struct ToUpperTraits {
5796 typedef unibrow::ToUppercase UnibrowConverter;
5797
lrn@chromium.org303ada72010-10-27 09:33:13 +00005798 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005799};
5800
5801} // namespace
5802
5803
5804template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005805MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005806 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005807 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005808 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005809 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005810 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005811 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005812
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005813 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005814 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005815 if (length == 0) return s;
5816
5817 // Simpler handling of ascii strings.
5818 //
5819 // NOTE: This assumes that the upper/lower case of an ascii
5820 // character is also ascii. This is currently the case, but it
5821 // might break in the future if we implement more context and locale
5822 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005823 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005824 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005825 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005826 if (!maybe_o->ToObject(&o)) return maybe_o;
5827 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005828 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005829 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005830 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005831 return has_changed_character ? result : s;
5832 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005833
lrn@chromium.org303ada72010-10-27 09:33:13 +00005834 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005835 { MaybeObject* maybe_answer =
5836 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005837 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5838 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005839 if (answer->IsSmi()) {
5840 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005841 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005842 ConvertCaseHelper(isolate,
5843 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005844 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5845 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005846 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005847 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005848}
5849
5850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005851RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005852 return ConvertCase<ToLowerTraits>(
5853 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854}
5855
5856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005857RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005858 return ConvertCase<ToUpperTraits>(
5859 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005860}
5861
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005862
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005863static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5864 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5865}
5866
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005868RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005869 NoHandleAllocation ha;
5870 ASSERT(args.length() == 3);
5871
5872 CONVERT_CHECKED(String, s, args[0]);
5873 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5874 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5875
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005876 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005877 int length = s->length();
5878
5879 int left = 0;
5880 if (trimLeft) {
5881 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5882 left++;
5883 }
5884 }
5885
5886 int right = length;
5887 if (trimRight) {
5888 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5889 right--;
5890 }
5891 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005892 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005893}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005894
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005895
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005896void FindAsciiStringIndices(Vector<const char> subject,
5897 char pattern,
5898 ZoneList<int>* indices,
5899 unsigned int limit) {
5900 ASSERT(limit > 0);
5901 // Collect indices of pattern in subject using memchr.
5902 // Stop after finding at most limit values.
5903 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5904 const char* subject_end = subject_start + subject.length();
5905 const char* pos = subject_start;
5906 while (limit > 0) {
5907 pos = reinterpret_cast<const char*>(
5908 memchr(pos, pattern, subject_end - pos));
5909 if (pos == NULL) return;
5910 indices->Add(static_cast<int>(pos - subject_start));
5911 pos++;
5912 limit--;
5913 }
5914}
5915
5916
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005917template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005918void FindStringIndices(Isolate* isolate,
5919 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005920 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005921 ZoneList<int>* indices,
5922 unsigned int limit) {
5923 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005924 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005925 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005926 int pattern_length = pattern.length();
5927 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005928 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005929 while (limit > 0) {
5930 index = search.Search(subject, index);
5931 if (index < 0) return;
5932 indices->Add(index);
5933 index += pattern_length;
5934 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005935 }
5936}
5937
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005939RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005940 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005941 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005942 CONVERT_ARG_CHECKED(String, subject, 0);
5943 CONVERT_ARG_CHECKED(String, pattern, 1);
5944 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5945
5946 int subject_length = subject->length();
5947 int pattern_length = pattern->length();
5948 RUNTIME_ASSERT(pattern_length > 0);
5949
5950 // The limit can be very large (0xffffffffu), but since the pattern
5951 // isn't empty, we can never create more parts than ~half the length
5952 // of the subject.
5953
5954 if (!subject->IsFlat()) FlattenString(subject);
5955
5956 static const int kMaxInitialListCapacity = 16;
5957
danno@chromium.org40cb8782011-05-25 07:58:50 +00005958 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005959
5960 // Find (up to limit) indices of separator and end-of-string in subject
5961 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5962 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005963 if (!pattern->IsFlat()) FlattenString(pattern);
5964
5965 // No allocation block.
5966 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005967 AssertNoAllocation nogc;
5968 if (subject->IsAsciiRepresentation()) {
5969 Vector<const char> subject_vector = subject->ToAsciiVector();
5970 if (pattern->IsAsciiRepresentation()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005971 Vector<const char> pattern_vector = pattern->ToAsciiVector();
5972 if (pattern_vector.length() == 1) {
5973 FindAsciiStringIndices(subject_vector,
5974 pattern_vector[0],
5975 &indices,
5976 limit);
5977 } else {
5978 FindStringIndices(isolate,
5979 subject_vector,
5980 pattern_vector,
5981 &indices,
5982 limit);
5983 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005984 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005985 FindStringIndices(isolate,
5986 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005987 pattern->ToUC16Vector(),
5988 &indices,
5989 limit);
5990 }
5991 } else {
5992 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5993 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005994 FindStringIndices(isolate,
5995 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005996 pattern->ToAsciiVector(),
5997 &indices,
5998 limit);
5999 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000 FindStringIndices(isolate,
6001 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006002 pattern->ToUC16Vector(),
6003 &indices,
6004 limit);
6005 }
6006 }
6007 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006008
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006009 if (static_cast<uint32_t>(indices.length()) < limit) {
6010 indices.Add(subject_length);
6011 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006012
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006013 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006014
6015 // Create JSArray of substrings separated by separator.
6016 int part_count = indices.length();
6017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006018 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006019 result->set_length(Smi::FromInt(part_count));
6020
6021 ASSERT(result->HasFastElements());
6022
6023 if (part_count == 1 && indices.at(0) == subject_length) {
6024 FixedArray::cast(result->elements())->set(0, *subject);
6025 return *result;
6026 }
6027
6028 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6029 int part_start = 0;
6030 for (int i = 0; i < part_count; i++) {
6031 HandleScope local_loop_handle;
6032 int part_end = indices.at(i);
6033 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006034 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006035 elements->set(i, *substring);
6036 part_start = part_end + pattern_length;
6037 }
6038
6039 return *result;
6040}
6041
6042
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006043// Copies ascii characters to the given fixed array looking up
6044// one-char strings in the cache. Gives up on the first char that is
6045// not in the cache and fills the remainder with smi zeros. Returns
6046// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006047static int CopyCachedAsciiCharsToArray(Heap* heap,
6048 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006049 FixedArray* elements,
6050 int length) {
6051 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006052 FixedArray* ascii_cache = heap->single_character_string_cache();
6053 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006054 int i;
6055 for (i = 0; i < length; ++i) {
6056 Object* value = ascii_cache->get(chars[i]);
6057 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006058 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006059 elements->set(i, value, SKIP_WRITE_BARRIER);
6060 }
6061 if (i < length) {
6062 ASSERT(Smi::FromInt(0) == 0);
6063 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6064 }
6065#ifdef DEBUG
6066 for (int j = 0; j < length; ++j) {
6067 Object* element = elements->get(j);
6068 ASSERT(element == Smi::FromInt(0) ||
6069 (element->IsString() && String::cast(element)->LooksValid()));
6070 }
6071#endif
6072 return i;
6073}
6074
6075
6076// Converts a String to JSArray.
6077// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006078RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006079 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006080 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006081 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006082 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006083
6084 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006085 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006086
6087 Handle<FixedArray> elements;
6088 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006089 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006090 { MaybeObject* maybe_obj =
6091 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006092 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6093 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006094 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006095
6096 Vector<const char> chars = s->ToAsciiVector();
6097 // Note, this will initialize all elements (not only the prefix)
6098 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006099 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
6100 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006101 *elements,
6102 length);
6103
6104 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006105 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
6106 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006107 }
6108 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006109 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006110 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006111 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6112 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006113 }
6114 }
6115
6116#ifdef DEBUG
6117 for (int i = 0; i < length; ++i) {
6118 ASSERT(String::cast(elements->get(i))->length() == 1);
6119 }
6120#endif
6121
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006122 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006123}
6124
6125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006126RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006127 NoHandleAllocation ha;
6128 ASSERT(args.length() == 1);
6129 CONVERT_CHECKED(String, value, args[0]);
6130 return value->ToObject();
6131}
6132
6133
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006134bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006135 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006136 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006137 return char_length == 0;
6138}
6139
6140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006141RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006142 NoHandleAllocation ha;
6143 ASSERT(args.length() == 1);
6144
6145 Object* number = args[0];
6146 RUNTIME_ASSERT(number->IsNumber());
6147
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006148 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006149}
6150
6151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006152RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006153 NoHandleAllocation ha;
6154 ASSERT(args.length() == 1);
6155
6156 Object* number = args[0];
6157 RUNTIME_ASSERT(number->IsNumber());
6158
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006159 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006160}
6161
6162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006163RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006164 NoHandleAllocation ha;
6165 ASSERT(args.length() == 1);
6166
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006167 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006168
6169 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6170 if (number > 0 && number <= Smi::kMaxValue) {
6171 return Smi::FromInt(static_cast<int>(number));
6172 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006173 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006174}
6175
6176
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006177RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006178 NoHandleAllocation ha;
6179 ASSERT(args.length() == 1);
6180
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006181 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006182
6183 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6184 if (number > 0 && number <= Smi::kMaxValue) {
6185 return Smi::FromInt(static_cast<int>(number));
6186 }
6187
6188 double double_value = DoubleToInteger(number);
6189 // Map both -0 and +0 to +0.
6190 if (double_value == 0) double_value = 0;
6191
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006192 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006193}
6194
6195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006196RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006197 NoHandleAllocation ha;
6198 ASSERT(args.length() == 1);
6199
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006200 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006201 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006202}
6203
6204
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006205RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006206 NoHandleAllocation ha;
6207 ASSERT(args.length() == 1);
6208
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006209 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006210
6211 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6212 if (number > 0 && number <= Smi::kMaxValue) {
6213 return Smi::FromInt(static_cast<int>(number));
6214 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006215 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006216}
6217
6218
ager@chromium.org870a0b62008-11-04 11:43:05 +00006219// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6220// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006221RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006222 NoHandleAllocation ha;
6223 ASSERT(args.length() == 1);
6224
6225 Object* obj = args[0];
6226 if (obj->IsSmi()) {
6227 return obj;
6228 }
6229 if (obj->IsHeapNumber()) {
6230 double value = HeapNumber::cast(obj)->value();
6231 int int_value = FastD2I(value);
6232 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6233 return Smi::FromInt(int_value);
6234 }
6235 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006236 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006237}
6238
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006240RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006241 NoHandleAllocation ha;
6242 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006243 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006244}
6245
6246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006247RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006248 NoHandleAllocation ha;
6249 ASSERT(args.length() == 2);
6250
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006251 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6252 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006253 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006254}
6255
6256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006257RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006258 NoHandleAllocation ha;
6259 ASSERT(args.length() == 2);
6260
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006261 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6262 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006263 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006264}
6265
6266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006267RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006268 NoHandleAllocation ha;
6269 ASSERT(args.length() == 2);
6270
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006271 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6272 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006273 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006274}
6275
6276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006277RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006278 NoHandleAllocation ha;
6279 ASSERT(args.length() == 1);
6280
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006281 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006282 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006283}
6284
6285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006286RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006287 NoHandleAllocation ha;
6288 ASSERT(args.length() == 0);
6289
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006290 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006291}
6292
6293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006294RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006295 NoHandleAllocation ha;
6296 ASSERT(args.length() == 2);
6297
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006298 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6299 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006300 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006301}
6302
6303
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006304RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006305 NoHandleAllocation ha;
6306 ASSERT(args.length() == 2);
6307
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006308 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6309 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006310
ager@chromium.org3811b432009-10-28 14:53:37 +00006311 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006312 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006313 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006314}
6315
6316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006317RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006318 NoHandleAllocation ha;
6319 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320 CONVERT_CHECKED(String, str1, args[0]);
6321 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006322 isolate->counters()->string_add_runtime()->Increment();
6323 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006324}
6325
6326
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006327template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006328static inline void StringBuilderConcatHelper(String* special,
6329 sinkchar* sink,
6330 FixedArray* fixed_array,
6331 int array_length) {
6332 int position = 0;
6333 for (int i = 0; i < array_length; i++) {
6334 Object* element = fixed_array->get(i);
6335 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006336 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006337 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006338 int pos;
6339 int len;
6340 if (encoded_slice > 0) {
6341 // Position and length encoded in one smi.
6342 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6343 len = StringBuilderSubstringLength::decode(encoded_slice);
6344 } else {
6345 // Position and length encoded in two smis.
6346 Object* obj = fixed_array->get(++i);
6347 ASSERT(obj->IsSmi());
6348 pos = Smi::cast(obj)->value();
6349 len = -encoded_slice;
6350 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006351 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006352 sink + position,
6353 pos,
6354 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006355 position += len;
6356 } else {
6357 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006358 int element_length = string->length();
6359 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006360 position += element_length;
6361 }
6362 }
6363}
6364
6365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006366RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006367 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006368 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006369 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006370 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006371 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006372 return Failure::OutOfMemoryException();
6373 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006374 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006375 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006376
6377 // This assumption is used by the slice encoding in one or two smis.
6378 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6379
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006380 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006381 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006382 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006383 }
6384 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006385 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006386 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006387 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006388
6389 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006390 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006391 } else if (array_length == 1) {
6392 Object* first = fixed_array->get(0);
6393 if (first->IsString()) return first;
6394 }
6395
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006396 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006397 int position = 0;
6398 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006399 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006400 Object* elt = fixed_array->get(i);
6401 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006402 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006403 int smi_value = Smi::cast(elt)->value();
6404 int pos;
6405 int len;
6406 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006407 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006408 pos = StringBuilderSubstringPosition::decode(smi_value);
6409 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006410 } else {
6411 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006412 len = -smi_value;
6413 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006414 i++;
6415 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006416 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006417 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006418 Object* next_smi = fixed_array->get(i);
6419 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006420 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006421 }
6422 pos = Smi::cast(next_smi)->value();
6423 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006424 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006425 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006426 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006427 ASSERT(pos >= 0);
6428 ASSERT(len >= 0);
6429 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006430 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006431 }
6432 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006433 } else if (elt->IsString()) {
6434 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006435 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006436 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006437 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006438 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006439 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006440 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006441 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006442 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006443 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006444 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006445 return Failure::OutOfMemoryException();
6446 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006447 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006448 }
6449
6450 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006451 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006452
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006454 { MaybeObject* maybe_object =
6455 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006456 if (!maybe_object->ToObject(&object)) return maybe_object;
6457 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006458 SeqAsciiString* answer = SeqAsciiString::cast(object);
6459 StringBuilderConcatHelper(special,
6460 answer->GetChars(),
6461 fixed_array,
6462 array_length);
6463 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006464 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006465 { MaybeObject* maybe_object =
6466 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006467 if (!maybe_object->ToObject(&object)) return maybe_object;
6468 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006469 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6470 StringBuilderConcatHelper(special,
6471 answer->GetChars(),
6472 fixed_array,
6473 array_length);
6474 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006475 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006476}
6477
6478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006479RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006480 NoHandleAllocation ha;
6481 ASSERT(args.length() == 3);
6482 CONVERT_CHECKED(JSArray, array, args[0]);
6483 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006484 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006485 return Failure::OutOfMemoryException();
6486 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006487 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006488 CONVERT_CHECKED(String, separator, args[2]);
6489
6490 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006491 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006492 }
6493 FixedArray* fixed_array = FixedArray::cast(array->elements());
6494 if (fixed_array->length() < array_length) {
6495 array_length = fixed_array->length();
6496 }
6497
6498 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006499 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006500 } else if (array_length == 1) {
6501 Object* first = fixed_array->get(0);
6502 if (first->IsString()) return first;
6503 }
6504
6505 int separator_length = separator->length();
6506 int max_nof_separators =
6507 (String::kMaxLength + separator_length - 1) / separator_length;
6508 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006509 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006510 return Failure::OutOfMemoryException();
6511 }
6512 int length = (array_length - 1) * separator_length;
6513 for (int i = 0; i < array_length; i++) {
6514 Object* element_obj = fixed_array->get(i);
6515 if (!element_obj->IsString()) {
6516 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006517 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006518 }
6519 String* element = String::cast(element_obj);
6520 int increment = element->length();
6521 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006522 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006523 return Failure::OutOfMemoryException();
6524 }
6525 length += increment;
6526 }
6527
6528 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006529 { MaybeObject* maybe_object =
6530 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006531 if (!maybe_object->ToObject(&object)) return maybe_object;
6532 }
6533 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6534
6535 uc16* sink = answer->GetChars();
6536#ifdef DEBUG
6537 uc16* end = sink + length;
6538#endif
6539
6540 String* first = String::cast(fixed_array->get(0));
6541 int first_length = first->length();
6542 String::WriteToFlat(first, sink, 0, first_length);
6543 sink += first_length;
6544
6545 for (int i = 1; i < array_length; i++) {
6546 ASSERT(sink + separator_length <= end);
6547 String::WriteToFlat(separator, sink, 0, separator_length);
6548 sink += separator_length;
6549
6550 String* element = String::cast(fixed_array->get(i));
6551 int element_length = element->length();
6552 ASSERT(sink + element_length <= end);
6553 String::WriteToFlat(element, sink, 0, element_length);
6554 sink += element_length;
6555 }
6556 ASSERT(sink == end);
6557
6558 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6559 return answer;
6560}
6561
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006562template <typename Char>
6563static void JoinSparseArrayWithSeparator(FixedArray* elements,
6564 int elements_length,
6565 uint32_t array_length,
6566 String* separator,
6567 Vector<Char> buffer) {
6568 int previous_separator_position = 0;
6569 int separator_length = separator->length();
6570 int cursor = 0;
6571 for (int i = 0; i < elements_length; i += 2) {
6572 int position = NumberToInt32(elements->get(i));
6573 String* string = String::cast(elements->get(i + 1));
6574 int string_length = string->length();
6575 if (string->length() > 0) {
6576 while (previous_separator_position < position) {
6577 String::WriteToFlat<Char>(separator, &buffer[cursor],
6578 0, separator_length);
6579 cursor += separator_length;
6580 previous_separator_position++;
6581 }
6582 String::WriteToFlat<Char>(string, &buffer[cursor],
6583 0, string_length);
6584 cursor += string->length();
6585 }
6586 }
6587 if (separator_length > 0) {
6588 // Array length must be representable as a signed 32-bit number,
6589 // otherwise the total string length would have been too large.
6590 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6591 int last_array_index = static_cast<int>(array_length - 1);
6592 while (previous_separator_position < last_array_index) {
6593 String::WriteToFlat<Char>(separator, &buffer[cursor],
6594 0, separator_length);
6595 cursor += separator_length;
6596 previous_separator_position++;
6597 }
6598 }
6599 ASSERT(cursor <= buffer.length());
6600}
6601
6602
6603RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6604 NoHandleAllocation ha;
6605 ASSERT(args.length() == 3);
6606 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6607 RUNTIME_ASSERT(elements_array->HasFastElements());
6608 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6609 CONVERT_CHECKED(String, separator, args[2]);
6610 // elements_array is fast-mode JSarray of alternating positions
6611 // (increasing order) and strings.
6612 // array_length is length of original array (used to add separators);
6613 // separator is string to put between elements. Assumed to be non-empty.
6614
6615 // Find total length of join result.
6616 int string_length = 0;
6617 bool is_ascii = true;
6618 int max_string_length = SeqAsciiString::kMaxLength;
6619 bool overflow = false;
6620 CONVERT_NUMBER_CHECKED(int, elements_length,
6621 Int32, elements_array->length());
6622 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6623 FixedArray* elements = FixedArray::cast(elements_array->elements());
6624 for (int i = 0; i < elements_length; i += 2) {
6625 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6626 CONVERT_CHECKED(String, string, elements->get(i + 1));
6627 int length = string->length();
6628 if (is_ascii && !string->IsAsciiRepresentation()) {
6629 is_ascii = false;
6630 max_string_length = SeqTwoByteString::kMaxLength;
6631 }
6632 if (length > max_string_length ||
6633 max_string_length - length < string_length) {
6634 overflow = true;
6635 break;
6636 }
6637 string_length += length;
6638 }
6639 int separator_length = separator->length();
6640 if (!overflow && separator_length > 0) {
6641 if (array_length <= 0x7fffffffu) {
6642 int separator_count = static_cast<int>(array_length) - 1;
6643 int remaining_length = max_string_length - string_length;
6644 if ((remaining_length / separator_length) >= separator_count) {
6645 string_length += separator_length * (array_length - 1);
6646 } else {
6647 // Not room for the separators within the maximal string length.
6648 overflow = true;
6649 }
6650 } else {
6651 // Nonempty separator and at least 2^31-1 separators necessary
6652 // means that the string is too large to create.
6653 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6654 overflow = true;
6655 }
6656 }
6657 if (overflow) {
6658 // Throw OutOfMemory exception for creating too large a string.
6659 V8::FatalProcessOutOfMemory("Array join result too large.");
6660 }
6661
6662 if (is_ascii) {
6663 MaybeObject* result_allocation =
6664 isolate->heap()->AllocateRawAsciiString(string_length);
6665 if (result_allocation->IsFailure()) return result_allocation;
6666 SeqAsciiString* result_string =
6667 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6668 JoinSparseArrayWithSeparator<char>(elements,
6669 elements_length,
6670 array_length,
6671 separator,
6672 Vector<char>(result_string->GetChars(),
6673 string_length));
6674 return result_string;
6675 } else {
6676 MaybeObject* result_allocation =
6677 isolate->heap()->AllocateRawTwoByteString(string_length);
6678 if (result_allocation->IsFailure()) return result_allocation;
6679 SeqTwoByteString* result_string =
6680 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6681 JoinSparseArrayWithSeparator<uc16>(elements,
6682 elements_length,
6683 array_length,
6684 separator,
6685 Vector<uc16>(result_string->GetChars(),
6686 string_length));
6687 return result_string;
6688 }
6689}
6690
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006692RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693 NoHandleAllocation ha;
6694 ASSERT(args.length() == 2);
6695
6696 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6697 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006698 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006699}
6700
6701
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006702RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006703 NoHandleAllocation ha;
6704 ASSERT(args.length() == 2);
6705
6706 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6707 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006708 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006709}
6710
6711
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006712RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006713 NoHandleAllocation ha;
6714 ASSERT(args.length() == 2);
6715
6716 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6717 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006718 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006719}
6720
6721
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006722RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006723 NoHandleAllocation ha;
6724 ASSERT(args.length() == 1);
6725
6726 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006727 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728}
6729
6730
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006731RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006732 NoHandleAllocation ha;
6733 ASSERT(args.length() == 2);
6734
6735 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6736 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006737 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006738}
6739
6740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006741RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006742 NoHandleAllocation ha;
6743 ASSERT(args.length() == 2);
6744
6745 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6746 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006747 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006748}
6749
6750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006751RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006752 NoHandleAllocation ha;
6753 ASSERT(args.length() == 2);
6754
6755 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6756 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006757 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006758}
6759
6760
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006761RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762 NoHandleAllocation ha;
6763 ASSERT(args.length() == 2);
6764
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006765 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6766 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6768 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6769 if (x == y) return Smi::FromInt(EQUAL);
6770 Object* result;
6771 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6772 result = Smi::FromInt(EQUAL);
6773 } else {
6774 result = Smi::FromInt(NOT_EQUAL);
6775 }
6776 return result;
6777}
6778
6779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006780RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006781 NoHandleAllocation ha;
6782 ASSERT(args.length() == 2);
6783
6784 CONVERT_CHECKED(String, x, args[0]);
6785 CONVERT_CHECKED(String, y, args[1]);
6786
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006787 bool not_equal = !x->Equals(y);
6788 // This is slightly convoluted because the value that signifies
6789 // equality is 0 and inequality is 1 so we have to negate the result
6790 // from String::Equals.
6791 ASSERT(not_equal == 0 || not_equal == 1);
6792 STATIC_CHECK(EQUAL == 0);
6793 STATIC_CHECK(NOT_EQUAL == 1);
6794 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795}
6796
6797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006798RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006799 NoHandleAllocation ha;
6800 ASSERT(args.length() == 3);
6801
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006802 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6803 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006804 if (isnan(x) || isnan(y)) return args[2];
6805 if (x == y) return Smi::FromInt(EQUAL);
6806 if (isless(x, y)) return Smi::FromInt(LESS);
6807 return Smi::FromInt(GREATER);
6808}
6809
6810
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006811// Compare two Smis as if they were converted to strings and then
6812// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006813RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006814 NoHandleAllocation ha;
6815 ASSERT(args.length() == 2);
6816
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006817 // Extract the integer values from the Smis.
6818 CONVERT_CHECKED(Smi, x, args[0]);
6819 CONVERT_CHECKED(Smi, y, args[1]);
6820 int x_value = x->value();
6821 int y_value = y->value();
6822
6823 // If the integers are equal so are the string representations.
6824 if (x_value == y_value) return Smi::FromInt(EQUAL);
6825
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006826 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006827 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006828 if (x_value == 0 || y_value == 0)
6829 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006830
ager@chromium.org32912102009-01-16 10:38:43 +00006831 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006832 // smallest because the char code of '-' is less than the char code
6833 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006834
6835 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6836 // architectures using 32-bit Smis.
6837 uint32_t x_scaled = x_value;
6838 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006839 if (x_value < 0 || y_value < 0) {
6840 if (y_value >= 0) return Smi::FromInt(LESS);
6841 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006842 x_scaled = -x_value;
6843 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006844 }
6845
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006846 static const uint32_t kPowersOf10[] = {
6847 1, 10, 100, 1000, 10*1000, 100*1000,
6848 1000*1000, 10*1000*1000, 100*1000*1000,
6849 1000*1000*1000
6850 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006851
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006852 // If the integers have the same number of decimal digits they can be
6853 // compared directly as the numeric order is the same as the
6854 // lexicographic order. If one integer has fewer digits, it is scaled
6855 // by some power of 10 to have the same number of digits as the longer
6856 // integer. If the scaled integers are equal it means the shorter
6857 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006858
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006859 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6860 int x_log2 = IntegerLog2(x_scaled);
6861 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6862 x_log10 -= x_scaled < kPowersOf10[x_log10];
6863
6864 int y_log2 = IntegerLog2(y_scaled);
6865 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6866 y_log10 -= y_scaled < kPowersOf10[y_log10];
6867
6868 int tie = EQUAL;
6869
6870 if (x_log10 < y_log10) {
6871 // X has fewer digits. We would like to simply scale up X but that
6872 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6873 // be scaled up to 9_000_000_000. So we scale up by the next
6874 // smallest power and scale down Y to drop one digit. It is OK to
6875 // drop one digit from the longer integer since the final digit is
6876 // past the length of the shorter integer.
6877 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6878 y_scaled /= 10;
6879 tie = LESS;
6880 } else if (y_log10 < x_log10) {
6881 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6882 x_scaled /= 10;
6883 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006884 }
6885
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006886 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6887 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6888 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006889}
6890
6891
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006892static Object* StringInputBufferCompare(RuntimeState* state,
6893 String* x,
6894 String* y) {
6895 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6896 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006897 bufx.Reset(x);
6898 bufy.Reset(y);
6899 while (bufx.has_more() && bufy.has_more()) {
6900 int d = bufx.GetNext() - bufy.GetNext();
6901 if (d < 0) return Smi::FromInt(LESS);
6902 else if (d > 0) return Smi::FromInt(GREATER);
6903 }
6904
6905 // x is (non-trivial) prefix of y:
6906 if (bufy.has_more()) return Smi::FromInt(LESS);
6907 // y is prefix of x:
6908 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6909}
6910
6911
6912static Object* FlatStringCompare(String* x, String* y) {
6913 ASSERT(x->IsFlat());
6914 ASSERT(y->IsFlat());
6915 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6916 int prefix_length = x->length();
6917 if (y->length() < prefix_length) {
6918 prefix_length = y->length();
6919 equal_prefix_result = Smi::FromInt(GREATER);
6920 } else if (y->length() > prefix_length) {
6921 equal_prefix_result = Smi::FromInt(LESS);
6922 }
6923 int r;
6924 if (x->IsAsciiRepresentation()) {
6925 Vector<const char> x_chars = x->ToAsciiVector();
6926 if (y->IsAsciiRepresentation()) {
6927 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006928 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006929 } else {
6930 Vector<const uc16> y_chars = y->ToUC16Vector();
6931 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6932 }
6933 } else {
6934 Vector<const uc16> x_chars = x->ToUC16Vector();
6935 if (y->IsAsciiRepresentation()) {
6936 Vector<const char> y_chars = y->ToAsciiVector();
6937 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6938 } else {
6939 Vector<const uc16> y_chars = y->ToUC16Vector();
6940 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6941 }
6942 }
6943 Object* result;
6944 if (r == 0) {
6945 result = equal_prefix_result;
6946 } else {
6947 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6948 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006949 ASSERT(result ==
6950 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006951 return result;
6952}
6953
6954
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006955RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006956 NoHandleAllocation ha;
6957 ASSERT(args.length() == 2);
6958
6959 CONVERT_CHECKED(String, x, args[0]);
6960 CONVERT_CHECKED(String, y, args[1]);
6961
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006962 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006963
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006964 // A few fast case tests before we flatten.
6965 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006966 if (y->length() == 0) {
6967 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006968 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006969 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006970 return Smi::FromInt(LESS);
6971 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006972
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006973 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006974 if (d < 0) return Smi::FromInt(LESS);
6975 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006976
lrn@chromium.org303ada72010-10-27 09:33:13 +00006977 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006978 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006979 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6980 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006981 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006982 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006984
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006985 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006986 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006987}
6988
6989
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006990RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006991 NoHandleAllocation ha;
6992 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006993 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006994
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006995 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006996 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006997}
6998
6999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007000RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007001 NoHandleAllocation ha;
7002 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007003 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007004
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007005 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007006 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007007}
7008
7009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007010RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007011 NoHandleAllocation ha;
7012 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007013 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007014
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007015 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007016 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007017}
7018
7019
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007020static const double kPiDividedBy4 = 0.78539816339744830962;
7021
7022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007023RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007024 NoHandleAllocation ha;
7025 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007026 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007027
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007028 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7029 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007030 double result;
7031 if (isinf(x) && isinf(y)) {
7032 // Make sure that the result in case of two infinite arguments
7033 // is a multiple of Pi / 4. The sign of the result is determined
7034 // by the first argument (x) and the sign of the second argument
7035 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007036 int multiplier = (x < 0) ? -1 : 1;
7037 if (y < 0) multiplier *= 3;
7038 result = multiplier * kPiDividedBy4;
7039 } else {
7040 result = atan2(x, y);
7041 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007042 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043}
7044
7045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007046RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007047 NoHandleAllocation ha;
7048 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007049 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007051 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007052 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053}
7054
7055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007056RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007057 NoHandleAllocation ha;
7058 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007059 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007060
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007061 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007062 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007063}
7064
7065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007066RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007067 NoHandleAllocation ha;
7068 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007069 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007070
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007071 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007072 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007073}
7074
7075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007076RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077 NoHandleAllocation ha;
7078 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007079 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007080
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007081 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007082 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007083}
7084
7085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007086RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007087 NoHandleAllocation ha;
7088 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007089 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007090
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007091 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007092 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093}
7094
7095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007096RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007097 NoHandleAllocation ha;
7098 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007099 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007101 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007102
7103 // If the second argument is a smi, it is much faster to call the
7104 // custom powi() function than the generic pow().
7105 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007106 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007107 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007108 }
7109
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007110 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007111 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007112}
7113
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007114// Fast version of Math.pow if we know that y is not an integer and
7115// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007116RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007117 NoHandleAllocation ha;
7118 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007119 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7120 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007121 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007122 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007123 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007124 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007125 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007126 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007127 }
7128}
7129
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007130
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007131RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007132 NoHandleAllocation ha;
7133 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007134 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007135
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007136 if (!args[0]->IsHeapNumber()) {
7137 // Must be smi. Return the argument unchanged for all the other types
7138 // to make fuzz-natives test happy.
7139 return args[0];
7140 }
7141
7142 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7143
7144 double value = number->value();
7145 int exponent = number->get_exponent();
7146 int sign = number->get_sign();
7147
danno@chromium.org160a7b02011-04-18 15:51:38 +00007148 if (exponent < -1) {
7149 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7150 if (sign) return isolate->heap()->minus_zero_value();
7151 return Smi::FromInt(0);
7152 }
7153
7154 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7155 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7156 // agument holds for 32-bit smis).
7157 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007158 return Smi::FromInt(static_cast<int>(value + 0.5));
7159 }
7160
7161 // If the magnitude is big enough, there's no place for fraction part. If we
7162 // try to add 0.5 to this number, 1.0 will be added instead.
7163 if (exponent >= 52) {
7164 return number;
7165 }
7166
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007167 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007168
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007169 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007170 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007171}
7172
7173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007174RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007175 NoHandleAllocation ha;
7176 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007177 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007178
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007179 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007180 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007181}
7182
7183
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007184RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007185 NoHandleAllocation ha;
7186 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007187 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007188
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007189 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007190 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007191}
7192
7193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007194RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007195 NoHandleAllocation ha;
7196 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007197 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007198
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007199 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007200 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007201}
7202
7203
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007204static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007205 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7206 181, 212, 243, 273, 304, 334};
7207 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7208 182, 213, 244, 274, 305, 335};
7209
7210 year += month / 12;
7211 month %= 12;
7212 if (month < 0) {
7213 year--;
7214 month += 12;
7215 }
7216
7217 ASSERT(month >= 0);
7218 ASSERT(month < 12);
7219
7220 // year_delta is an arbitrary number such that:
7221 // a) year_delta = -1 (mod 400)
7222 // b) year + year_delta > 0 for years in the range defined by
7223 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7224 // Jan 1 1970. This is required so that we don't run into integer
7225 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007226 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007227 // operations.
7228 static const int year_delta = 399999;
7229 static const int base_day = 365 * (1970 + year_delta) +
7230 (1970 + year_delta) / 4 -
7231 (1970 + year_delta) / 100 +
7232 (1970 + year_delta) / 400;
7233
7234 int year1 = year + year_delta;
7235 int day_from_year = 365 * year1 +
7236 year1 / 4 -
7237 year1 / 100 +
7238 year1 / 400 -
7239 base_day;
7240
7241 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007242 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007243 }
7244
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007245 return day_from_year + day_from_month_leap[month] + day - 1;
7246}
7247
7248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007249RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007250 NoHandleAllocation ha;
7251 ASSERT(args.length() == 3);
7252
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007253 CONVERT_SMI_ARG_CHECKED(year, 0);
7254 CONVERT_SMI_ARG_CHECKED(month, 1);
7255 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007256
7257 return Smi::FromInt(MakeDay(year, month, date));
7258}
7259
7260
7261static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7262static const int kDaysIn4Years = 4 * 365 + 1;
7263static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7264static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7265static const int kDays1970to2000 = 30 * 365 + 7;
7266static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7267 kDays1970to2000;
7268static const int kYearsOffset = 400000;
7269
7270static const char kDayInYear[] = {
7271 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7272 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7273 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7274 22, 23, 24, 25, 26, 27, 28,
7275 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7276 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7277 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7278 22, 23, 24, 25, 26, 27, 28, 29, 30,
7279 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7280 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7281 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7282 22, 23, 24, 25, 26, 27, 28, 29, 30,
7283 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7284 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7285 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7286 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7287 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7288 22, 23, 24, 25, 26, 27, 28, 29, 30,
7289 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7290 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7291 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7292 22, 23, 24, 25, 26, 27, 28, 29, 30,
7293 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7294 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7295
7296 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7297 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7298 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7299 22, 23, 24, 25, 26, 27, 28,
7300 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7301 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7302 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7303 22, 23, 24, 25, 26, 27, 28, 29, 30,
7304 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7305 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7306 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7307 22, 23, 24, 25, 26, 27, 28, 29, 30,
7308 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7309 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7310 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7311 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7312 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7313 22, 23, 24, 25, 26, 27, 28, 29, 30,
7314 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7315 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7316 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7317 22, 23, 24, 25, 26, 27, 28, 29, 30,
7318 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7319 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7320
7321 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7322 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7323 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7324 22, 23, 24, 25, 26, 27, 28, 29,
7325 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7326 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7327 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7328 22, 23, 24, 25, 26, 27, 28, 29, 30,
7329 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7330 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7331 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7332 22, 23, 24, 25, 26, 27, 28, 29, 30,
7333 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7334 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7335 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7336 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7337 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7338 22, 23, 24, 25, 26, 27, 28, 29, 30,
7339 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7340 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7341 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7342 22, 23, 24, 25, 26, 27, 28, 29, 30,
7343 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7344 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7345
7346 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7347 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7348 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7349 22, 23, 24, 25, 26, 27, 28,
7350 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7351 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7352 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7353 22, 23, 24, 25, 26, 27, 28, 29, 30,
7354 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7355 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7356 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7357 22, 23, 24, 25, 26, 27, 28, 29, 30,
7358 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7359 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7360 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7361 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7362 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7363 22, 23, 24, 25, 26, 27, 28, 29, 30,
7364 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7365 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7366 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7367 22, 23, 24, 25, 26, 27, 28, 29, 30,
7368 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7369 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7370
7371static const char kMonthInYear[] = {
7372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7373 0, 0, 0, 0, 0, 0,
7374 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7375 1, 1, 1,
7376 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7377 2, 2, 2, 2, 2, 2,
7378 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7379 3, 3, 3, 3, 3,
7380 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7381 4, 4, 4, 4, 4, 4,
7382 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7383 5, 5, 5, 5, 5,
7384 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7385 6, 6, 6, 6, 6, 6,
7386 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7387 7, 7, 7, 7, 7, 7,
7388 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7389 8, 8, 8, 8, 8,
7390 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7391 9, 9, 9, 9, 9, 9,
7392 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7393 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7394 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7395 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7396
7397 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7398 0, 0, 0, 0, 0, 0,
7399 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7400 1, 1, 1,
7401 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7402 2, 2, 2, 2, 2, 2,
7403 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7404 3, 3, 3, 3, 3,
7405 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7406 4, 4, 4, 4, 4, 4,
7407 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7408 5, 5, 5, 5, 5,
7409 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7410 6, 6, 6, 6, 6, 6,
7411 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7412 7, 7, 7, 7, 7, 7,
7413 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7414 8, 8, 8, 8, 8,
7415 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7416 9, 9, 9, 9, 9, 9,
7417 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7418 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7419 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7420 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7421
7422 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7423 0, 0, 0, 0, 0, 0,
7424 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7425 1, 1, 1, 1,
7426 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7427 2, 2, 2, 2, 2, 2,
7428 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7429 3, 3, 3, 3, 3,
7430 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7431 4, 4, 4, 4, 4, 4,
7432 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7433 5, 5, 5, 5, 5,
7434 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7435 6, 6, 6, 6, 6, 6,
7436 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7437 7, 7, 7, 7, 7, 7,
7438 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7439 8, 8, 8, 8, 8,
7440 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7441 9, 9, 9, 9, 9, 9,
7442 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7443 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7444 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7445 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7446
7447 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7448 0, 0, 0, 0, 0, 0,
7449 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7450 1, 1, 1,
7451 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7452 2, 2, 2, 2, 2, 2,
7453 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7454 3, 3, 3, 3, 3,
7455 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7456 4, 4, 4, 4, 4, 4,
7457 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7458 5, 5, 5, 5, 5,
7459 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7460 6, 6, 6, 6, 6, 6,
7461 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7462 7, 7, 7, 7, 7, 7,
7463 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7464 8, 8, 8, 8, 8,
7465 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7466 9, 9, 9, 9, 9, 9,
7467 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7468 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7469 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7470 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7471
7472
7473// This function works for dates from 1970 to 2099.
7474static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007475 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007476#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007477 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007478#endif
7479
7480 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7481 date %= kDaysIn4Years;
7482
7483 month = kMonthInYear[date];
7484 day = kDayInYear[date];
7485
7486 ASSERT(MakeDay(year, month, day) == save_date);
7487}
7488
7489
7490static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007491 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007492#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007493 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007494#endif
7495
7496 date += kDaysOffset;
7497 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7498 date %= kDaysIn400Years;
7499
7500 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7501
7502 date--;
7503 int yd1 = date / kDaysIn100Years;
7504 date %= kDaysIn100Years;
7505 year += 100 * yd1;
7506
7507 date++;
7508 int yd2 = date / kDaysIn4Years;
7509 date %= kDaysIn4Years;
7510 year += 4 * yd2;
7511
7512 date--;
7513 int yd3 = date / 365;
7514 date %= 365;
7515 year += yd3;
7516
7517 bool is_leap = (!yd1 || yd2) && !yd3;
7518
7519 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007520 ASSERT(is_leap || (date >= 0));
7521 ASSERT((date < 365) || (is_leap && (date < 366)));
7522 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7523 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7524 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007525
7526 if (is_leap) {
7527 day = kDayInYear[2*365 + 1 + date];
7528 month = kMonthInYear[2*365 + 1 + date];
7529 } else {
7530 day = kDayInYear[date];
7531 month = kMonthInYear[date];
7532 }
7533
7534 ASSERT(MakeDay(year, month, day) == save_date);
7535}
7536
7537
7538static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007539 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007540 if (date >= 0 && date < 32 * kDaysIn4Years) {
7541 DateYMDFromTimeAfter1970(date, year, month, day);
7542 } else {
7543 DateYMDFromTimeSlow(date, year, month, day);
7544 }
7545}
7546
7547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007548RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007549 NoHandleAllocation ha;
7550 ASSERT(args.length() == 2);
7551
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007552 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007553 CONVERT_CHECKED(JSArray, res_array, args[1]);
7554
7555 int year, month, day;
7556 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7557
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007558 RUNTIME_ASSERT(res_array->elements()->map() ==
7559 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007560 FixedArray* elms = FixedArray::cast(res_array->elements());
7561 RUNTIME_ASSERT(elms->length() == 3);
7562
7563 elms->set(0, Smi::FromInt(year));
7564 elms->set(1, Smi::FromInt(month));
7565 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007566
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007567 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007568}
7569
7570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007571RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007572 HandleScope scope(isolate);
7573 ASSERT(args.length() == 3);
7574
7575 Handle<JSFunction> callee = args.at<JSFunction>(0);
7576 Object** parameters = reinterpret_cast<Object**>(args[1]);
7577 const int argument_count = Smi::cast(args[2])->value();
7578
7579 Handle<JSObject> result =
7580 isolate->factory()->NewArgumentsObject(callee, argument_count);
7581 // Allocate the elements if needed.
7582 int parameter_count = callee->shared()->formal_parameter_count();
7583 if (argument_count > 0) {
7584 if (parameter_count > 0) {
7585 int mapped_count = Min(argument_count, parameter_count);
7586 Handle<FixedArray> parameter_map =
7587 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7588 parameter_map->set_map(
7589 isolate->heap()->non_strict_arguments_elements_map());
7590
7591 Handle<Map> old_map(result->map());
7592 Handle<Map> new_map =
7593 isolate->factory()->CopyMapDropTransitions(old_map);
7594 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7595
7596 result->set_map(*new_map);
7597 result->set_elements(*parameter_map);
7598
7599 // Store the context and the arguments array at the beginning of the
7600 // parameter map.
7601 Handle<Context> context(isolate->context());
7602 Handle<FixedArray> arguments =
7603 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7604 parameter_map->set(0, *context);
7605 parameter_map->set(1, *arguments);
7606
7607 // Loop over the actual parameters backwards.
7608 int index = argument_count - 1;
7609 while (index >= mapped_count) {
7610 // These go directly in the arguments array and have no
7611 // corresponding slot in the parameter map.
7612 arguments->set(index, *(parameters - index - 1));
7613 --index;
7614 }
7615
7616 ScopeInfo<> scope_info(callee->shared()->scope_info());
7617 while (index >= 0) {
7618 // Detect duplicate names to the right in the parameter list.
7619 Handle<String> name = scope_info.parameter_name(index);
7620 int context_slot_count = scope_info.number_of_context_slots();
7621 bool duplicate = false;
7622 for (int j = index + 1; j < parameter_count; ++j) {
7623 if (scope_info.parameter_name(j).is_identical_to(name)) {
7624 duplicate = true;
7625 break;
7626 }
7627 }
7628
7629 if (duplicate) {
7630 // This goes directly in the arguments array with a hole in the
7631 // parameter map.
7632 arguments->set(index, *(parameters - index - 1));
7633 parameter_map->set_the_hole(index + 2);
7634 } else {
7635 // The context index goes in the parameter map with a hole in the
7636 // arguments array.
7637 int context_index = -1;
7638 for (int j = Context::MIN_CONTEXT_SLOTS;
7639 j < context_slot_count;
7640 ++j) {
7641 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7642 context_index = j;
7643 break;
7644 }
7645 }
7646 ASSERT(context_index >= 0);
7647 arguments->set_the_hole(index);
7648 parameter_map->set(index + 2, Smi::FromInt(context_index));
7649 }
7650
7651 --index;
7652 }
7653 } else {
7654 // If there is no aliasing, the arguments object elements are not
7655 // special in any way.
7656 Handle<FixedArray> elements =
7657 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7658 result->set_elements(*elements);
7659 for (int i = 0; i < argument_count; ++i) {
7660 elements->set(i, *(parameters - i - 1));
7661 }
7662 }
7663 }
7664 return *result;
7665}
7666
7667
7668RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007669 NoHandleAllocation ha;
7670 ASSERT(args.length() == 3);
7671
7672 JSFunction* callee = JSFunction::cast(args[0]);
7673 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007674 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007675
lrn@chromium.org303ada72010-10-27 09:33:13 +00007676 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007677 { MaybeObject* maybe_result =
7678 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007679 if (!maybe_result->ToObject(&result)) return maybe_result;
7680 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007681 // Allocate the elements if needed.
7682 if (length > 0) {
7683 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007684 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007685 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007686 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7687 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007688
7689 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007690 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007691 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007692 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007693
7694 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007695 for (int i = 0; i < length; i++) {
7696 array->set(i, *--parameters, mode);
7697 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007698 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007699 }
7700 return result;
7701}
7702
7703
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007704RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007705 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007706 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007707 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007708 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007709 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007710
whesse@chromium.org7b260152011-06-20 15:33:18 +00007711 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007712 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007713 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007714 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007715 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7716 context,
7717 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007718 return *result;
7719}
7720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007721
7722static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7723 int* total_argc) {
7724 // Find frame containing arguments passed to the caller.
7725 JavaScriptFrameIterator it;
7726 JavaScriptFrame* frame = it.frame();
7727 List<JSFunction*> functions(2);
7728 frame->GetFunctions(&functions);
7729 if (functions.length() > 1) {
7730 int inlined_frame_index = functions.length() - 1;
7731 JSFunction* inlined_function = functions[inlined_frame_index];
7732 int args_count = inlined_function->shared()->formal_parameter_count();
7733 ScopedVector<SlotRef> args_slots(args_count);
7734 SlotRef::ComputeSlotMappingForArguments(frame,
7735 inlined_frame_index,
7736 &args_slots);
7737
7738 *total_argc = bound_argc + args_count;
7739 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7740 for (int i = 0; i < args_count; i++) {
7741 Handle<Object> val = args_slots[i].GetValue();
7742 param_data[bound_argc + i] = val.location();
7743 }
7744 return param_data;
7745 } else {
7746 it.AdvanceToArgumentsFrame();
7747 frame = it.frame();
7748 int args_count = frame->ComputeParametersCount();
7749
7750 *total_argc = bound_argc + args_count;
7751 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7752 for (int i = 0; i < args_count; i++) {
7753 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7754 param_data[bound_argc + i] = val.location();
7755 }
7756 return param_data;
7757 }
7758}
7759
7760
7761RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007762 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007763 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007764 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007765 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007766
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007767 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007768 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007769 int bound_argc = 0;
7770 if (!args[1]->IsNull()) {
7771 CONVERT_ARG_CHECKED(JSArray, params, 1);
7772 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007773 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007774 bound_argc = Smi::cast(params->length())->value();
7775 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007777 int total_argc = 0;
7778 SmartPointer<Object**> param_data =
7779 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007780 for (int i = 0; i < bound_argc; i++) {
7781 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007782 param_data[i] = val.location();
7783 }
7784
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007785 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007786 Handle<Object> result =
7787 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007788 if (exception) {
7789 return Failure::Exception();
7790 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007791
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007792 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007793 return *result;
7794}
7795
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007796
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007797static void TrySettingInlineConstructStub(Isolate* isolate,
7798 Handle<JSFunction> function) {
7799 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007800 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007801 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007802 }
7803 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007804 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007805 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007806 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007807 function->shared()->set_construct_stub(
7808 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007809 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007810 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007811}
7812
7813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007814RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007815 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007816 ASSERT(args.length() == 1);
7817
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007818 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007819
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007820 // If the constructor isn't a proper function we throw a type error.
7821 if (!constructor->IsJSFunction()) {
7822 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7823 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007824 isolate->factory()->NewTypeError("not_constructor", arguments);
7825 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007826 }
7827
7828 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007829
7830 // If function should not have prototype, construction is not allowed. In this
7831 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007832 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007833 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7834 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007835 isolate->factory()->NewTypeError("not_constructor", arguments);
7836 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007837 }
7838
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007839#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007840 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007841 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007842 if (debug->StepInActive()) {
7843 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007844 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007845#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007846
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007847 if (function->has_initial_map()) {
7848 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007849 // The 'Function' function ignores the receiver object when
7850 // called using 'new' and creates a new JSFunction object that
7851 // is returned. The receiver object is only used for error
7852 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007853 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007854 // allocate JSFunctions since it does not properly initialize
7855 // the shared part of the function. Since the receiver is
7856 // ignored anyway, we use the global object as the receiver
7857 // instead of a new JSFunction object. This way, errors are
7858 // reported the same way whether or not 'Function' is called
7859 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007860 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007861 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007862 }
7863
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007864 // The function should be compiled for the optimization hints to be
7865 // available. We cannot use EnsureCompiled because that forces a
7866 // compilation through the shared function info which makes it
7867 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007868 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007869 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007870
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007871 if (!function->has_initial_map() &&
7872 shared->IsInobjectSlackTrackingInProgress()) {
7873 // The tracking is already in progress for another function. We can only
7874 // track one initial_map at a time, so we force the completion before the
7875 // function is called as a constructor for the first time.
7876 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007877 }
7878
7879 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007880 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7881 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007882 // Delay setting the stub if inobject slack tracking is in progress.
7883 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007884 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007885 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007886
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007887 isolate->counters()->constructed_objects()->Increment();
7888 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007889
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007890 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007891}
7892
7893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007894RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007895 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007896 ASSERT(args.length() == 1);
7897
7898 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7899 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007900 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007901
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007902 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007903}
7904
7905
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007906RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007907 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007908 ASSERT(args.length() == 1);
7909
7910 Handle<JSFunction> function = args.at<JSFunction>(0);
7911#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007912 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007913 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007914 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007915 PrintF("]\n");
7916 }
7917#endif
7918
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007919 // Compile the target function. Here we compile using CompileLazyInLoop in
7920 // order to get the optimized version. This helps code like delta-blue
7921 // that calls performance-critical routines through constructors. A
7922 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7923 // direct call. Since the in-loop tracking takes place through CallICs
7924 // this means that things called through constructors are never known to
7925 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007926 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007927 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007928 return Failure::Exception();
7929 }
7930
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007931 // All done. Return the compiled code.
7932 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007933 return function->code();
7934}
7935
7936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007937RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007938 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007939 ASSERT(args.length() == 1);
7940 Handle<JSFunction> function = args.at<JSFunction>(0);
7941 // If the function is not optimizable or debugger is active continue using the
7942 // code from the full compiler.
7943 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007944 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007945 if (FLAG_trace_opt) {
7946 PrintF("[failed to optimize ");
7947 function->PrintName();
7948 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7949 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007950 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007951 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007952 function->ReplaceCode(function->shared()->code());
7953 return function->code();
7954 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007955 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007956 return function->code();
7957 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007958 if (FLAG_trace_opt) {
7959 PrintF("[failed to optimize ");
7960 function->PrintName();
7961 PrintF(": optimized compilation failed]\n");
7962 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007963 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007964 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007965}
7966
7967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007968RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007969 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007970 ASSERT(args.length() == 1);
7971 RUNTIME_ASSERT(args[0]->IsSmi());
7972 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007973 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007974 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7975 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007976 int frames = deoptimizer->output_count();
7977
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007978 deoptimizer->MaterializeHeapNumbers();
7979 delete deoptimizer;
7980
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007981 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007982 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007983 for (int i = 0; i < frames - 1; i++) it.Advance();
7984 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007985
7986 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007987 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007988 Handle<Object> arguments;
7989 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007990 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007991 if (arguments.is_null()) {
7992 // FunctionGetArguments can't throw an exception, so cast away the
7993 // doubt with an assert.
7994 arguments = Handle<Object>(
7995 Accessors::FunctionGetArguments(*function,
7996 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007997 ASSERT(*arguments != isolate->heap()->null_value());
7998 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007999 }
8000 frame->SetExpression(i, *arguments);
8001 }
8002 }
8003
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008004 if (type == Deoptimizer::EAGER) {
8005 RUNTIME_ASSERT(function->IsOptimized());
8006 } else {
8007 RUNTIME_ASSERT(!function->IsOptimized());
8008 }
8009
8010 // Avoid doing too much work when running with --always-opt and keep
8011 // the optimized code around.
8012 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008013 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008014 }
8015
8016 // Count the number of optimized activations of the function.
8017 int activations = 0;
8018 while (!it.done()) {
8019 JavaScriptFrame* frame = it.frame();
8020 if (frame->is_optimized() && frame->function() == *function) {
8021 activations++;
8022 }
8023 it.Advance();
8024 }
8025
8026 // TODO(kasperl): For now, we cannot support removing the optimized
8027 // code when we have recursive invocations of the same function.
8028 if (activations == 0) {
8029 if (FLAG_trace_deopt) {
8030 PrintF("[removing optimized code for: ");
8031 function->PrintName();
8032 PrintF("]\n");
8033 }
8034 function->ReplaceCode(function->shared()->code());
8035 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008036 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008037}
8038
8039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008040RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008041 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008042 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008043 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008044}
8045
8046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008047RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008048 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008049 ASSERT(args.length() == 1);
8050 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008051 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008052
8053 Deoptimizer::DeoptimizeFunction(*function);
8054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008055 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008056}
8057
8058
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008059RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8060#if defined(USE_SIMULATOR)
8061 return isolate->heap()->true_value();
8062#else
8063 return isolate->heap()->false_value();
8064#endif
8065}
8066
8067
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008068RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8069 HandleScope scope(isolate);
8070 ASSERT(args.length() == 1);
8071 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8072 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8073 function->MarkForLazyRecompilation();
8074 return isolate->heap()->undefined_value();
8075}
8076
8077
lrn@chromium.org1c092762011-05-09 09:42:16 +00008078RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8079 HandleScope scope(isolate);
8080 ASSERT(args.length() == 1);
8081 if (!V8::UseCrankshaft()) {
8082 return Smi::FromInt(4); // 4 == "never".
8083 }
8084 if (FLAG_always_opt) {
8085 return Smi::FromInt(3); // 3 == "always".
8086 }
8087 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8088 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8089 : Smi::FromInt(2); // 2 == "no".
8090}
8091
8092
8093RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8094 HandleScope scope(isolate);
8095 ASSERT(args.length() == 1);
8096 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8097 return Smi::FromInt(function->shared()->opt_count());
8098}
8099
8100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008101RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008102 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008103 ASSERT(args.length() == 1);
8104 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8105
8106 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008107 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008108
8109 // We have hit a back edge in an unoptimized frame for a function that was
8110 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008111 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008112 // Keep track of whether we've succeeded in optimizing.
8113 bool succeeded = unoptimized->optimizable();
8114 if (succeeded) {
8115 // If we are trying to do OSR when there are already optimized
8116 // activations of the function, it means (a) the function is directly or
8117 // indirectly recursive and (b) an optimized invocation has been
8118 // deoptimized so that we are currently in an unoptimized activation.
8119 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008120 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008121 while (succeeded && !it.done()) {
8122 JavaScriptFrame* frame = it.frame();
8123 succeeded = !frame->is_optimized() || frame->function() != *function;
8124 it.Advance();
8125 }
8126 }
8127
8128 int ast_id = AstNode::kNoNumber;
8129 if (succeeded) {
8130 // The top JS function is this one, the PC is somewhere in the
8131 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008132 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008133 JavaScriptFrame* frame = it.frame();
8134 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008135 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008136 ASSERT(unoptimized->contains(frame->pc()));
8137
8138 // Use linear search of the unoptimized code's stack check table to find
8139 // the AST id matching the PC.
8140 Address start = unoptimized->instruction_start();
8141 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008142 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008143 uint32_t table_length = Memory::uint32_at(table_cursor);
8144 table_cursor += kIntSize;
8145 for (unsigned i = 0; i < table_length; ++i) {
8146 // Table entries are (AST id, pc offset) pairs.
8147 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8148 if (pc_offset == target_pc_offset) {
8149 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8150 break;
8151 }
8152 table_cursor += 2 * kIntSize;
8153 }
8154 ASSERT(ast_id != AstNode::kNoNumber);
8155 if (FLAG_trace_osr) {
8156 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8157 function->PrintName();
8158 PrintF("]\n");
8159 }
8160
8161 // Try to compile the optimized code. A true return value from
8162 // CompileOptimized means that compilation succeeded, not necessarily
8163 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008164 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8165 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008166 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8167 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008168 if (data->OsrPcOffset()->value() >= 0) {
8169 if (FLAG_trace_osr) {
8170 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008171 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008172 }
8173 ASSERT(data->OsrAstId()->value() == ast_id);
8174 } else {
8175 // We may never generate the desired OSR entry if we emit an
8176 // early deoptimize.
8177 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008178 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008179 } else {
8180 succeeded = false;
8181 }
8182 }
8183
8184 // Revert to the original stack checks in the original unoptimized code.
8185 if (FLAG_trace_osr) {
8186 PrintF("[restoring original stack checks in ");
8187 function->PrintName();
8188 PrintF("]\n");
8189 }
8190 StackCheckStub check_stub;
8191 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008192 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008193 Deoptimizer::RevertStackCheckCode(*unoptimized,
8194 *check_code,
8195 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008196
8197 // Allow OSR only at nesting level zero again.
8198 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8199
8200 // If the optimization attempt succeeded, return the AST id tagged as a
8201 // smi. This tells the builtin that we need to translate the unoptimized
8202 // frame to an optimized one.
8203 if (succeeded) {
8204 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8205 return Smi::FromInt(ast_id);
8206 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008207 if (function->IsMarkedForLazyRecompilation()) {
8208 function->ReplaceCode(function->shared()->code());
8209 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008210 return Smi::FromInt(-1);
8211 }
8212}
8213
8214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008215RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008216 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008217 ASSERT(args.length() == 1);
8218 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8219 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8220}
8221
8222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008223RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008224 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008225 ASSERT(args.length() == 1);
8226 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8227 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8228}
8229
8230
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008231RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008232 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008233 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008234
kasper.lund7276f142008-07-30 08:49:36 +00008235 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008236 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008237 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008238 { MaybeObject* maybe_result =
8239 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008240 if (!maybe_result->ToObject(&result)) return maybe_result;
8241 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008242
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008243 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008244
kasper.lund7276f142008-07-30 08:49:36 +00008245 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008246}
8247
lrn@chromium.org303ada72010-10-27 09:33:13 +00008248
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008249RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8250 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008251 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008252 JSObject* extension_object;
8253 if (args[0]->IsJSObject()) {
8254 extension_object = JSObject::cast(args[0]);
8255 } else {
8256 // Convert the object to a proper JavaScript object.
8257 MaybeObject* maybe_js_object = args[0]->ToObject();
8258 if (!maybe_js_object->To(&extension_object)) {
8259 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8260 HandleScope scope(isolate);
8261 Handle<Object> handle = args.at<Object>(0);
8262 Handle<Object> result =
8263 isolate->factory()->NewTypeError("with_expression",
8264 HandleVector(&handle, 1));
8265 return isolate->Throw(*result);
8266 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008267 return maybe_js_object;
8268 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008269 }
8270 }
8271
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008272 JSFunction* function;
8273 if (args[1]->IsSmi()) {
8274 // A smi sentinel indicates a context nested inside global code rather
8275 // than some function. There is a canonical empty function that can be
8276 // gotten from the global context.
8277 function = isolate->context()->global_context()->closure();
8278 } else {
8279 function = JSFunction::cast(args[1]);
8280 }
8281
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008282 Context* context;
8283 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008284 isolate->heap()->AllocateWithContext(function,
8285 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008286 extension_object);
8287 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008288 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008289 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008290}
8291
8292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008293RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008294 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008295 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008296 String* name = String::cast(args[0]);
8297 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008298 JSFunction* function;
8299 if (args[2]->IsSmi()) {
8300 // A smi sentinel indicates a context nested inside global code rather
8301 // than some function. There is a canonical empty function that can be
8302 // gotten from the global context.
8303 function = isolate->context()->global_context()->closure();
8304 } else {
8305 function = JSFunction::cast(args[2]);
8306 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008307 Context* context;
8308 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008309 isolate->heap()->AllocateCatchContext(function,
8310 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008311 name,
8312 thrown_object);
8313 if (!maybe_context->To(&context)) return maybe_context;
8314 isolate->set_context(context);
8315 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008316}
8317
8318
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008319RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8320 NoHandleAllocation ha;
8321 ASSERT(args.length() == 2);
8322 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8323 JSFunction* function;
8324 if (args[1]->IsSmi()) {
8325 // A smi sentinel indicates a context nested inside global code rather
8326 // than some function. There is a canonical empty function that can be
8327 // gotten from the global context.
8328 function = isolate->context()->global_context()->closure();
8329 } else {
8330 function = JSFunction::cast(args[1]);
8331 }
8332 Context* context;
8333 MaybeObject* maybe_context =
8334 isolate->heap()->AllocateBlockContext(function,
8335 isolate->context(),
8336 scope_info);
8337 if (!maybe_context->To(&context)) return maybe_context;
8338 isolate->set_context(context);
8339 return context;
8340}
8341
8342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008343RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008344 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008345 ASSERT(args.length() == 2);
8346
8347 CONVERT_ARG_CHECKED(Context, context, 0);
8348 CONVERT_ARG_CHECKED(String, name, 1);
8349
8350 int index;
8351 PropertyAttributes attributes;
8352 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008353 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008354
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008355 // If the slot was not found the result is true.
8356 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008357 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008358 }
8359
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008360 // If the slot was found in a context, it should be DONT_DELETE.
8361 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008362 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008363 }
8364
8365 // The slot was found in a JSObject, either a context extension object,
8366 // the global object, or an arguments object. Try to delete it
8367 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8368 // which allows deleting all parameters in functions that mention
8369 // 'arguments', we do this even for the case of slots found on an
8370 // arguments object. The slot was found on an arguments object if the
8371 // index is non-negative.
8372 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8373 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008374 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008375 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008376 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008377 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008378}
8379
8380
ager@chromium.orga1645e22009-09-09 19:27:10 +00008381// A mechanism to return a pair of Object pointers in registers (if possible).
8382// How this is achieved is calling convention-dependent.
8383// All currently supported x86 compiles uses calling conventions that are cdecl
8384// variants where a 64-bit value is returned in two 32-bit registers
8385// (edx:eax on ia32, r1:r0 on ARM).
8386// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8387// In Win64 calling convention, a struct of two pointers is returned in memory,
8388// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008389#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008390struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008391 MaybeObject* x;
8392 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008393};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008394
lrn@chromium.org303ada72010-10-27 09:33:13 +00008395static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008396 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008397 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8398 // In Win64 they are assigned to a hidden first argument.
8399 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008400}
8401#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008402typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008403static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008404 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008405 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008406}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008407#endif
8408
8409
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008410static inline MaybeObject* Unhole(Heap* heap,
8411 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008412 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008413 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8414 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008415 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008416}
8417
8418
danno@chromium.org40cb8782011-05-25 07:58:50 +00008419static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8420 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008421 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008422 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008423 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008424 JSFunction* context_extension_function =
8425 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008426 // If the holder isn't a context extension object, we just return it
8427 // as the receiver. This allows arguments objects to be used as
8428 // receivers, but only if they are put in the context scope chain
8429 // explicitly via a with-statement.
8430 Object* constructor = holder->map()->constructor();
8431 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008432 // Fall back to using the global object as the implicit receiver if
8433 // the property turns out to be a local variable allocated in a
8434 // context extension object - introduced via eval. Implicit global
8435 // receivers are indicated with the hole value.
8436 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008437}
8438
8439
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008440static ObjectPair LoadContextSlotHelper(Arguments args,
8441 Isolate* isolate,
8442 bool throw_error) {
8443 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008444 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008445
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008446 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008447 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008448 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008449 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008450 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008451
8452 int index;
8453 PropertyAttributes attributes;
8454 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008455 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008456
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008457 // If the index is non-negative, the slot has been found in a local
8458 // variable or a parameter. Read it from the context object or the
8459 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008460 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008461 // If the "property" we were looking for is a local variable or an
8462 // argument in a context, the receiver is the global object; see
8463 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008464 //
8465 // Use the hole as the receiver to signal that the receiver is
8466 // implicit and that the global receiver should be used.
8467 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008468 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008469 ? Context::cast(*holder)->get(index)
8470 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008471 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008472 }
8473
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008474 // If the holder is found, we read the property from it.
8475 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008476 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008477 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008478 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008479 if (object->IsGlobalObject()) {
8480 receiver = GlobalObject::cast(object)->global_receiver();
8481 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008482 // Use the hole as the receiver to signal that the receiver is
8483 // implicit and that the global receiver should be used.
8484 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008485 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008486 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008487 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008488
8489 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008490 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008491
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008492 // No need to unhole the value here. This is taken care of by the
8493 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008494 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008495 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008496 }
8497
8498 if (throw_error) {
8499 // The property doesn't exist - throw exception.
8500 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008501 isolate->factory()->NewReferenceError("not_defined",
8502 HandleVector(&name, 1));
8503 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008504 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008505 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008506 return MakePair(isolate->heap()->undefined_value(),
8507 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008508 }
8509}
8510
8511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008512RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008513 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008514}
8515
8516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008517RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008518 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008519}
8520
8521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008522RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008523 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008524 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008525
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008526 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008527 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008528 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008529 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008530 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8531 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008532 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008533
8534 int index;
8535 PropertyAttributes attributes;
8536 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008537 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008538
8539 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008540 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008541 // Ignore if read_only variable.
8542 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008543 // Context is a fixed array and set cannot fail.
8544 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008545 } else if (strict_mode == kStrictMode) {
8546 // Setting read only property in strict mode.
8547 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008548 isolate->factory()->NewTypeError("strict_cannot_assign",
8549 HandleVector(&name, 1));
8550 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008551 }
8552 } else {
8553 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008554 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008555 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008556 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008557 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008558 return Failure::Exception();
8559 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008560 }
8561 return *value;
8562 }
8563
8564 // Slow case: The property is not in a FixedArray context.
8565 // It is either in an JSObject extension context or it was not found.
8566 Handle<JSObject> context_ext;
8567
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008568 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008569 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008570 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008571 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008572 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008573 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008574
8575 if (strict_mode == kStrictMode) {
8576 // Throw in strict mode (assignment to undefined variable).
8577 Handle<Object> error =
8578 isolate->factory()->NewReferenceError(
8579 "not_defined", HandleVector(&name, 1));
8580 return isolate->Throw(*error);
8581 }
8582 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008583 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008584 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008585 }
8586
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008587 // Set the property, but ignore if read_only variable on the context
8588 // extension object itself.
8589 if ((attributes & READ_ONLY) == 0 ||
8590 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008591 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008592 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008593 SetProperty(context_ext, name, value, NONE, strict_mode));
8594 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008595 // Setting read only property in strict mode.
8596 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008597 isolate->factory()->NewTypeError(
8598 "strict_cannot_assign", HandleVector(&name, 1));
8599 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008600 }
8601 return *value;
8602}
8603
8604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008605RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008606 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008607 ASSERT(args.length() == 1);
8608
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008609 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008610}
8611
8612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008613RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008614 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008615 ASSERT(args.length() == 1);
8616
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008617 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008618}
8619
8620
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008621RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008622 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008623 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008624}
8625
8626
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008627RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008628 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008629 ASSERT(args.length() == 1);
8630
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008631 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008632 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008633 isolate->factory()->NewReferenceError("not_defined",
8634 HandleVector(&name, 1));
8635 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008636}
8637
8638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008639RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008640 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008641
8642 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008643 if (isolate->stack_guard()->IsStackOverflow()) {
8644 NoHandleAllocation na;
8645 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008646 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008647
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008648 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008649}
8650
8651
8652// NOTE: These PrintXXX functions are defined for all builds (not just
8653// DEBUG builds) because we may want to be able to trace function
8654// calls in all modes.
8655static void PrintString(String* str) {
8656 // not uncommon to have empty strings
8657 if (str->length() > 0) {
8658 SmartPointer<char> s =
8659 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8660 PrintF("%s", *s);
8661 }
8662}
8663
8664
8665static void PrintObject(Object* obj) {
8666 if (obj->IsSmi()) {
8667 PrintF("%d", Smi::cast(obj)->value());
8668 } else if (obj->IsString() || obj->IsSymbol()) {
8669 PrintString(String::cast(obj));
8670 } else if (obj->IsNumber()) {
8671 PrintF("%g", obj->Number());
8672 } else if (obj->IsFailure()) {
8673 PrintF("<failure>");
8674 } else if (obj->IsUndefined()) {
8675 PrintF("<undefined>");
8676 } else if (obj->IsNull()) {
8677 PrintF("<null>");
8678 } else if (obj->IsTrue()) {
8679 PrintF("<true>");
8680 } else if (obj->IsFalse()) {
8681 PrintF("<false>");
8682 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008683 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008684 }
8685}
8686
8687
8688static int StackSize() {
8689 int n = 0;
8690 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8691 return n;
8692}
8693
8694
8695static void PrintTransition(Object* result) {
8696 // indentation
8697 { const int nmax = 80;
8698 int n = StackSize();
8699 if (n <= nmax)
8700 PrintF("%4d:%*s", n, n, "");
8701 else
8702 PrintF("%4d:%*s", n, nmax, "...");
8703 }
8704
8705 if (result == NULL) {
8706 // constructor calls
8707 JavaScriptFrameIterator it;
8708 JavaScriptFrame* frame = it.frame();
8709 if (frame->IsConstructor()) PrintF("new ");
8710 // function name
8711 Object* fun = frame->function();
8712 if (fun->IsJSFunction()) {
8713 PrintObject(JSFunction::cast(fun)->shared()->name());
8714 } else {
8715 PrintObject(fun);
8716 }
8717 // function arguments
8718 // (we are intentionally only printing the actually
8719 // supplied parameters, not all parameters required)
8720 PrintF("(this=");
8721 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008722 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008723 for (int i = 0; i < length; i++) {
8724 PrintF(", ");
8725 PrintObject(frame->GetParameter(i));
8726 }
8727 PrintF(") {\n");
8728
8729 } else {
8730 // function result
8731 PrintF("} -> ");
8732 PrintObject(result);
8733 PrintF("\n");
8734 }
8735}
8736
8737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008738RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008739 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008740 NoHandleAllocation ha;
8741 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008742 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008743}
8744
8745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008746RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008747 NoHandleAllocation ha;
8748 PrintTransition(args[0]);
8749 return args[0]; // return TOS
8750}
8751
8752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008753RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008754 NoHandleAllocation ha;
8755 ASSERT(args.length() == 1);
8756
8757#ifdef DEBUG
8758 if (args[0]->IsString()) {
8759 // If we have a string, assume it's a code "marker"
8760 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008761 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008762 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008763 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8764 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008765 } else {
8766 PrintF("DebugPrint: ");
8767 }
8768 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008769 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008770 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008771 HeapObject::cast(args[0])->map()->Print();
8772 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008773#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008774 // ShortPrint is available in release mode. Print is not.
8775 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008776#endif
8777 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008778 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008779
8780 return args[0]; // return TOS
8781}
8782
8783
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008784RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008785 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008786 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008787 isolate->PrintStack();
8788 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008789}
8790
8791
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008792RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008793 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008794 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008795
8796 // According to ECMA-262, section 15.9.1, page 117, the precision of
8797 // the number in a Date object representing a particular instant in
8798 // time is milliseconds. Therefore, we floor the result of getting
8799 // the OS time.
8800 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008801 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008802}
8803
8804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008805RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008806 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008807 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008808
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008809 CONVERT_ARG_CHECKED(String, str, 0);
8810 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008811
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008812 CONVERT_ARG_CHECKED(JSArray, output, 1);
8813 RUNTIME_ASSERT(output->HasFastElements());
8814
8815 AssertNoAllocation no_allocation;
8816
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008817 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008818 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8819 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008820 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008821 result = DateParser::Parse(str->ToAsciiVector(),
8822 output_array,
8823 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008824 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008825 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008826 result = DateParser::Parse(str->ToUC16Vector(),
8827 output_array,
8828 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008829 }
8830
8831 if (result) {
8832 return *output;
8833 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008834 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008835 }
8836}
8837
8838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008839RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008840 NoHandleAllocation ha;
8841 ASSERT(args.length() == 1);
8842
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008843 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008844 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008845 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008846}
8847
8848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008849RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008850 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008851 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008853 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008854}
8855
8856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008857RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008858 NoHandleAllocation ha;
8859 ASSERT(args.length() == 1);
8860
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008861 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008862 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008863}
8864
8865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008866RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008867 ASSERT(args.length() == 1);
8868 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008869 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008870 return JSGlobalObject::cast(global)->global_receiver();
8871}
8872
8873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008874RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008875 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008876 ASSERT_EQ(1, args.length());
8877 CONVERT_ARG_CHECKED(String, source, 0);
8878
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008879 source = Handle<String>(source->TryFlattenGetString());
8880 // Optimized fast case where we only have ascii characters.
8881 Handle<Object> result;
8882 if (source->IsSeqAsciiString()) {
8883 result = JsonParser<true>::Parse(source);
8884 } else {
8885 result = JsonParser<false>::Parse(source);
8886 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008887 if (result.is_null()) {
8888 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008889 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008890 return Failure::Exception();
8891 }
8892 return *result;
8893}
8894
8895
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008896bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8897 Handle<Context> context) {
8898 if (context->allow_code_gen_from_strings()->IsFalse()) {
8899 // Check with callback if set.
8900 AllowCodeGenerationFromStringsCallback callback =
8901 isolate->allow_code_gen_callback();
8902 if (callback == NULL) {
8903 // No callback set and code generation disallowed.
8904 return false;
8905 } else {
8906 // Callback set. Let it decide if code generation is allowed.
8907 VMState state(isolate, EXTERNAL);
8908 return callback(v8::Utils::ToLocal(context));
8909 }
8910 }
8911 return true;
8912}
8913
8914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008915RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008916 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008917 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008918 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008919
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008920 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008921 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008922
8923 // Check if global context allows code generation from
8924 // strings. Throw an exception if it doesn't.
8925 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8926 return isolate->Throw(*isolate->factory()->NewError(
8927 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8928 }
8929
8930 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008931 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8932 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008933 true,
8934 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008935 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008936 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008937 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8938 context,
8939 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008940 return *fun;
8941}
8942
8943
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008944static ObjectPair CompileGlobalEval(Isolate* isolate,
8945 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008946 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008947 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008948 Handle<Context> context = Handle<Context>(isolate->context());
8949 Handle<Context> global_context = Handle<Context>(context->global_context());
8950
8951 // Check if global context allows code generation from
8952 // strings. Throw an exception if it doesn't.
8953 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8954 isolate->Throw(*isolate->factory()->NewError(
8955 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8956 return MakePair(Failure::Exception(), NULL);
8957 }
8958
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008959 // Deal with a normal eval call with a string argument. Compile it
8960 // and return the compiled function bound in the local context.
8961 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8962 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008963 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008964 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008965 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008966 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008967 Handle<JSFunction> compiled =
8968 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008969 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008970 return MakePair(*compiled, *receiver);
8971}
8972
8973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008974RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008975 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008976
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008977 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008978 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008979 Handle<Object> receiver; // Will be overwritten.
8980
8981 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008982 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008983#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008984 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008985 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008986 StackFrameLocator locator;
8987 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008988 ASSERT(Context::cast(frame->context()) == *context);
8989#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008990
8991 // Find where the 'eval' symbol is bound. It is unaliased only if
8992 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008993 int index = -1;
8994 PropertyAttributes attributes = ABSENT;
8995 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008996 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8997 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008998 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008999 // Stop search when eval is found or when the global context is
9000 // reached.
9001 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009002 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009003 }
9004
iposva@chromium.org245aa852009-02-10 00:49:54 +00009005 // If eval could not be resolved, it has been deleted and we need to
9006 // throw a reference error.
9007 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009008 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009009 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009010 isolate->factory()->NewReferenceError("not_defined",
9011 HandleVector(&name, 1));
9012 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009013 }
9014
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009015 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009016 // 'eval' is not bound in the global context. Just call the function
9017 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009018 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009019 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009020 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009021 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009022 }
9023
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009024 // 'eval' is bound in the global context, but it may have been overwritten.
9025 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009026 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009027 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009028 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009029 }
9030
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009031 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009032 return CompileGlobalEval(isolate,
9033 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009034 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009035 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009036}
9037
9038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009039RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009040 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009041
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009042 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009043 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009044
9045 // 'eval' is bound in the global context, but it may have been overwritten.
9046 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009047 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009048 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009049 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009050 }
9051
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009052 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009053 return CompileGlobalEval(isolate,
9054 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009055 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009056 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009057}
9058
9059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009060RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009061 // This utility adjusts the property attributes for newly created Function
9062 // object ("new Function(...)") by changing the map.
9063 // All it does is changing the prototype property to enumerable
9064 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009065 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009066 ASSERT(args.length() == 1);
9067 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009068
9069 Handle<Map> map = func->shared()->strict_mode()
9070 ? isolate->strict_mode_function_instance_map()
9071 : isolate->function_instance_map();
9072
9073 ASSERT(func->map()->instance_type() == map->instance_type());
9074 ASSERT(func->map()->instance_size() == map->instance_size());
9075 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009076 return *func;
9077}
9078
9079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009080RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009081 // Allocate a block of memory in NewSpace (filled with a filler).
9082 // Use as fallback for allocation in generated code when NewSpace
9083 // is full.
9084 ASSERT(args.length() == 1);
9085 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9086 int size = size_smi->value();
9087 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9088 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009089 Heap* heap = isolate->heap();
9090 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009091 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009092 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009093 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009094 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009095 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009096 }
9097 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009098 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009099}
9100
9101
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009102// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009103// array. Returns true if the element was pushed on the stack and
9104// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009105RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009106 ASSERT(args.length() == 2);
9107 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009108 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009109 RUNTIME_ASSERT(array->HasFastElements());
9110 int length = Smi::cast(array->length())->value();
9111 FixedArray* elements = FixedArray::cast(array->elements());
9112 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009113 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009114 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009115 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009116 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009117 { MaybeObject* maybe_obj =
9118 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009119 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9120 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009121 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009122}
9123
9124
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009125/**
9126 * A simple visitor visits every element of Array's.
9127 * The backend storage can be a fixed array for fast elements case,
9128 * or a dictionary for sparse array. Since Dictionary is a subtype
9129 * of FixedArray, the class can be used by both fast and slow cases.
9130 * The second parameter of the constructor, fast_elements, specifies
9131 * whether the storage is a FixedArray or Dictionary.
9132 *
9133 * An index limit is used to deal with the situation that a result array
9134 * length overflows 32-bit non-negative integer.
9135 */
9136class ArrayConcatVisitor {
9137 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009138 ArrayConcatVisitor(Isolate* isolate,
9139 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009140 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009141 isolate_(isolate),
9142 storage_(Handle<FixedArray>::cast(
9143 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009144 index_offset_(0u),
9145 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009146
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009147 ~ArrayConcatVisitor() {
9148 clear_storage();
9149 }
9150
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009151 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009152 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009153 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009154
9155 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009156 if (index < static_cast<uint32_t>(storage_->length())) {
9157 storage_->set(index, *elm);
9158 return;
9159 }
9160 // Our initial estimate of length was foiled, possibly by
9161 // getters on the arrays increasing the length of later arrays
9162 // during iteration.
9163 // This shouldn't happen in anything but pathological cases.
9164 SetDictionaryMode(index);
9165 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009166 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009167 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009168 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009169 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009170 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009171 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009172 // Dictionary needed to grow.
9173 clear_storage();
9174 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009175 }
9176}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009177
9178 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009179 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9180 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009181 } else {
9182 index_offset_ += delta;
9183 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009184 }
9185
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009186 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009187 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009188 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009189 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009190 Handle<Map> map;
9191 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009192 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009193 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009194 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009195 }
9196 array->set_map(*map);
9197 array->set_length(*length);
9198 array->set_elements(*storage_);
9199 return array;
9200 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009201
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009202 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009203 // Convert storage to dictionary mode.
9204 void SetDictionaryMode(uint32_t index) {
9205 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009206 Handle<FixedArray> current_storage(*storage_);
9207 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009208 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009209 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9210 for (uint32_t i = 0; i < current_length; i++) {
9211 HandleScope loop_scope;
9212 Handle<Object> element(current_storage->get(i));
9213 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009214 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009215 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009216 if (!new_storage.is_identical_to(slow_storage)) {
9217 slow_storage = loop_scope.CloseAndEscape(new_storage);
9218 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009219 }
9220 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009221 clear_storage();
9222 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009223 fast_elements_ = false;
9224 }
9225
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009226 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009227 isolate_->global_handles()->Destroy(
9228 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009229 }
9230
9231 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009232 storage_ = Handle<FixedArray>::cast(
9233 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009234 }
9235
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009236 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009237 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009238 // Index after last seen index. Always less than or equal to
9239 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009240 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009241 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009242};
9243
9244
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009245static uint32_t EstimateElementCount(Handle<JSArray> array) {
9246 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9247 int element_count = 0;
9248 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009249 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009250 // Fast elements can't have lengths that are not representable by
9251 // a 32-bit signed integer.
9252 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9253 int fast_length = static_cast<int>(length);
9254 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9255 for (int i = 0; i < fast_length; i++) {
9256 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009257 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009258 break;
9259 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009260 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009261 Handle<NumberDictionary> dictionary(
9262 NumberDictionary::cast(array->elements()));
9263 int capacity = dictionary->Capacity();
9264 for (int i = 0; i < capacity; i++) {
9265 Handle<Object> key(dictionary->KeyAt(i));
9266 if (dictionary->IsKey(*key)) {
9267 element_count++;
9268 }
9269 }
9270 break;
9271 }
9272 default:
9273 // External arrays are always dense.
9274 return length;
9275 }
9276 // As an estimate, we assume that the prototype doesn't contain any
9277 // inherited elements.
9278 return element_count;
9279}
9280
9281
9282
9283template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009284static void IterateExternalArrayElements(Isolate* isolate,
9285 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009286 bool elements_are_ints,
9287 bool elements_are_guaranteed_smis,
9288 ArrayConcatVisitor* visitor) {
9289 Handle<ExternalArrayClass> array(
9290 ExternalArrayClass::cast(receiver->elements()));
9291 uint32_t len = static_cast<uint32_t>(array->length());
9292
9293 ASSERT(visitor != NULL);
9294 if (elements_are_ints) {
9295 if (elements_are_guaranteed_smis) {
9296 for (uint32_t j = 0; j < len; j++) {
9297 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009298 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009299 visitor->visit(j, e);
9300 }
9301 } else {
9302 for (uint32_t j = 0; j < len; j++) {
9303 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009304 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009305 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9306 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9307 visitor->visit(j, e);
9308 } else {
9309 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009310 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009311 visitor->visit(j, e);
9312 }
9313 }
9314 }
9315 } else {
9316 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009317 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009318 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009319 visitor->visit(j, e);
9320 }
9321 }
9322}
9323
9324
9325// Used for sorting indices in a List<uint32_t>.
9326static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9327 uint32_t a = *ap;
9328 uint32_t b = *bp;
9329 return (a == b) ? 0 : (a < b) ? -1 : 1;
9330}
9331
9332
9333static void CollectElementIndices(Handle<JSObject> object,
9334 uint32_t range,
9335 List<uint32_t>* indices) {
9336 JSObject::ElementsKind kind = object->GetElementsKind();
9337 switch (kind) {
9338 case JSObject::FAST_ELEMENTS: {
9339 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9340 uint32_t length = static_cast<uint32_t>(elements->length());
9341 if (range < length) length = range;
9342 for (uint32_t i = 0; i < length; i++) {
9343 if (!elements->get(i)->IsTheHole()) {
9344 indices->Add(i);
9345 }
9346 }
9347 break;
9348 }
9349 case JSObject::DICTIONARY_ELEMENTS: {
9350 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009351 uint32_t capacity = dict->Capacity();
9352 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009353 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009354 Handle<Object> k(dict->KeyAt(j));
9355 if (dict->IsKey(*k)) {
9356 ASSERT(k->IsNumber());
9357 uint32_t index = static_cast<uint32_t>(k->Number());
9358 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009359 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009360 }
9361 }
9362 }
9363 break;
9364 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009365 default: {
9366 int dense_elements_length;
9367 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009368 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009369 dense_elements_length =
9370 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009371 break;
9372 }
9373 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009374 dense_elements_length =
9375 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009376 break;
9377 }
9378 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009379 dense_elements_length =
9380 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009381 break;
9382 }
9383 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009384 dense_elements_length =
9385 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009386 break;
9387 }
9388 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009389 dense_elements_length =
9390 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009391 break;
9392 }
9393 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009394 dense_elements_length =
9395 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009396 break;
9397 }
9398 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009399 dense_elements_length =
9400 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009401 break;
9402 }
9403 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009404 dense_elements_length =
9405 ExternalFloatArray::cast(object->elements())->length();
9406 break;
9407 }
9408 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9409 dense_elements_length =
9410 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009411 break;
9412 }
9413 default:
9414 UNREACHABLE();
9415 dense_elements_length = 0;
9416 break;
9417 }
9418 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9419 if (range <= length) {
9420 length = range;
9421 // We will add all indices, so we might as well clear it first
9422 // and avoid duplicates.
9423 indices->Clear();
9424 }
9425 for (uint32_t i = 0; i < length; i++) {
9426 indices->Add(i);
9427 }
9428 if (length == range) return; // All indices accounted for already.
9429 break;
9430 }
9431 }
9432
9433 Handle<Object> prototype(object->GetPrototype());
9434 if (prototype->IsJSObject()) {
9435 // The prototype will usually have no inherited element indices,
9436 // but we have to check.
9437 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9438 }
9439}
9440
9441
9442/**
9443 * A helper function that visits elements of a JSArray in numerical
9444 * order.
9445 *
9446 * The visitor argument called for each existing element in the array
9447 * with the element index and the element's value.
9448 * Afterwards it increments the base-index of the visitor by the array
9449 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009450 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009451 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009452static bool IterateElements(Isolate* isolate,
9453 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009454 ArrayConcatVisitor* visitor) {
9455 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9456 switch (receiver->GetElementsKind()) {
9457 case JSObject::FAST_ELEMENTS: {
9458 // Run through the elements FixedArray and use HasElement and GetElement
9459 // to check the prototype for missing elements.
9460 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9461 int fast_length = static_cast<int>(length);
9462 ASSERT(fast_length <= elements->length());
9463 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009464 HandleScope loop_scope(isolate);
9465 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009466 if (!element_value->IsTheHole()) {
9467 visitor->visit(j, element_value);
9468 } else if (receiver->HasElement(j)) {
9469 // Call GetElement on receiver, not its prototype, or getters won't
9470 // have the correct receiver.
9471 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009472 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009473 visitor->visit(j, element_value);
9474 }
9475 }
9476 break;
9477 }
9478 case JSObject::DICTIONARY_ELEMENTS: {
9479 Handle<NumberDictionary> dict(receiver->element_dictionary());
9480 List<uint32_t> indices(dict->Capacity() / 2);
9481 // Collect all indices in the object and the prototypes less
9482 // than length. This might introduce duplicates in the indices list.
9483 CollectElementIndices(receiver, length, &indices);
9484 indices.Sort(&compareUInt32);
9485 int j = 0;
9486 int n = indices.length();
9487 while (j < n) {
9488 HandleScope loop_scope;
9489 uint32_t index = indices[j];
9490 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009491 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009492 visitor->visit(index, element);
9493 // Skip to next different index (i.e., omit duplicates).
9494 do {
9495 j++;
9496 } while (j < n && indices[j] == index);
9497 }
9498 break;
9499 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009500 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9501 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9502 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009503 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009504 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009505 visitor->visit(j, e);
9506 }
9507 break;
9508 }
9509 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9510 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009511 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009512 break;
9513 }
9514 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9515 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009516 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009517 break;
9518 }
9519 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9520 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009521 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009522 break;
9523 }
9524 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9525 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009526 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009527 break;
9528 }
9529 case JSObject::EXTERNAL_INT_ELEMENTS: {
9530 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009531 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009532 break;
9533 }
9534 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9535 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009536 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009537 break;
9538 }
9539 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9540 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009541 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009542 break;
9543 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009544 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9545 IterateExternalArrayElements<ExternalDoubleArray, double>(
9546 isolate, receiver, false, false, visitor);
9547 break;
9548 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009549 default:
9550 UNREACHABLE();
9551 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009552 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009553 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009554 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009555}
9556
9557
9558/**
9559 * Array::concat implementation.
9560 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009561 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009562 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009563 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009564RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009565 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009566 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009567
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009568 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9569 int argument_count = static_cast<int>(arguments->length()->Number());
9570 RUNTIME_ASSERT(arguments->HasFastElements());
9571 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009572
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009573 // Pass 1: estimate the length and number of elements of the result.
9574 // The actual length can be larger if any of the arguments have getters
9575 // that mutate other arguments (but will otherwise be precise).
9576 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009577
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009578 uint32_t estimate_result_length = 0;
9579 uint32_t estimate_nof_elements = 0;
9580 {
9581 for (int i = 0; i < argument_count; i++) {
9582 HandleScope loop_scope;
9583 Handle<Object> obj(elements->get(i));
9584 uint32_t length_estimate;
9585 uint32_t element_estimate;
9586 if (obj->IsJSArray()) {
9587 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9588 length_estimate =
9589 static_cast<uint32_t>(array->length()->Number());
9590 element_estimate =
9591 EstimateElementCount(array);
9592 } else {
9593 length_estimate = 1;
9594 element_estimate = 1;
9595 }
9596 // Avoid overflows by capping at kMaxElementCount.
9597 if (JSObject::kMaxElementCount - estimate_result_length <
9598 length_estimate) {
9599 estimate_result_length = JSObject::kMaxElementCount;
9600 } else {
9601 estimate_result_length += length_estimate;
9602 }
9603 if (JSObject::kMaxElementCount - estimate_nof_elements <
9604 element_estimate) {
9605 estimate_nof_elements = JSObject::kMaxElementCount;
9606 } else {
9607 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009608 }
9609 }
9610 }
9611
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009612 // If estimated number of elements is more than half of length, a
9613 // fixed array (fast case) is more time and space-efficient than a
9614 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009615 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009616
9617 Handle<FixedArray> storage;
9618 if (fast_case) {
9619 // The backing storage array must have non-existing elements to
9620 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009621 storage = isolate->factory()->NewFixedArrayWithHoles(
9622 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009623 } else {
9624 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9625 uint32_t at_least_space_for = estimate_nof_elements +
9626 (estimate_nof_elements >> 2);
9627 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009628 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009629 }
9630
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009631 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009632
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009633 for (int i = 0; i < argument_count; i++) {
9634 Handle<Object> obj(elements->get(i));
9635 if (obj->IsJSArray()) {
9636 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009637 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009638 return Failure::Exception();
9639 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009640 } else {
9641 visitor.visit(0, obj);
9642 visitor.increase_index_offset(1);
9643 }
9644 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009645
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009646 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009647}
9648
9649
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009650// This will not allocate (flatten the string), but it may run
9651// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009652RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009653 NoHandleAllocation ha;
9654 ASSERT(args.length() == 1);
9655
9656 CONVERT_CHECKED(String, string, args[0]);
9657 StringInputBuffer buffer(string);
9658 while (buffer.has_more()) {
9659 uint16_t character = buffer.GetNext();
9660 PrintF("%c", character);
9661 }
9662 return string;
9663}
9664
ager@chromium.org5ec48922009-05-05 07:25:34 +00009665// Moves all own elements of an object, that are below a limit, to positions
9666// starting at zero. All undefined values are placed after non-undefined values,
9667// and are followed by non-existing element. Does not change the length
9668// property.
9669// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009670RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009671 ASSERT(args.length() == 2);
9672 CONVERT_CHECKED(JSObject, object, args[0]);
9673 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9674 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009675}
9676
9677
9678// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009679RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009680 ASSERT(args.length() == 2);
9681 CONVERT_CHECKED(JSArray, from, args[0]);
9682 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009683 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009684 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009685 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9686 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009687 maybe_new_map = to->map()->GetFastElementsMap();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009688 } else if (new_elements->map() ==
9689 isolate->heap()->fixed_double_array_map()) {
9690 maybe_new_map = to->map()->GetFastDoubleElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009691 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009692 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009693 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009694 Object* new_map;
9695 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009696 to->set_map(Map::cast(new_map));
9697 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009698 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009699 Object* obj;
9700 { MaybeObject* maybe_obj = from->ResetElements();
9701 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9702 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009703 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009704 return to;
9705}
9706
9707
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009708// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009709RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009710 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009711 CONVERT_CHECKED(JSObject, object, args[0]);
9712 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009713 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009714 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009715 } else if (object->IsJSArray()) {
9716 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009717 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009718 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009719 }
9720}
9721
9722
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009723RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009724 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009725
9726 ASSERT_EQ(3, args.length());
9727
ager@chromium.orgac091b72010-05-05 07:34:42 +00009728 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009729 Handle<Object> key1 = args.at<Object>(1);
9730 Handle<Object> key2 = args.at<Object>(2);
9731
9732 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009733 if (!key1->ToArrayIndex(&index1)
9734 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009735 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009736 }
9737
ager@chromium.orgac091b72010-05-05 07:34:42 +00009738 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9739 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009740 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009741 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009742 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009743
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009744 RETURN_IF_EMPTY_HANDLE(isolate,
9745 SetElement(jsobject, index1, tmp2, kStrictMode));
9746 RETURN_IF_EMPTY_HANDLE(isolate,
9747 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009748
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009749 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009750}
9751
9752
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009753// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009754// might have elements. Can either return keys (positive integers) or
9755// intervals (pair of a negative integer (-start-1) followed by a
9756// positive (length)) or undefined values.
9757// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009758RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009759 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009760 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009761 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009762 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009763 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009764 // Create an array and get all the keys into it, then remove all the
9765 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009766 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009767 int keys_length = keys->length();
9768 for (int i = 0; i < keys_length; i++) {
9769 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009770 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009771 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009772 // Zap invalid keys.
9773 keys->set_undefined(i);
9774 }
9775 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009776 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009777 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009778 ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009779 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009780 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009781 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009782 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009783 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009784 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009785 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009786 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009787 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009788 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009789 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009790 }
9791}
9792
9793
9794// DefineAccessor takes an optional final argument which is the
9795// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9796// to the way accessors are implemented, it is set for both the getter
9797// and setter on the first call to DefineAccessor and ignored on
9798// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009799RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009800 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9801 // Compute attributes.
9802 PropertyAttributes attributes = NONE;
9803 if (args.length() == 5) {
9804 CONVERT_CHECKED(Smi, attrs, args[4]);
9805 int value = attrs->value();
9806 // Only attribute bits should be set.
9807 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9808 attributes = static_cast<PropertyAttributes>(value);
9809 }
9810
9811 CONVERT_CHECKED(JSObject, obj, args[0]);
9812 CONVERT_CHECKED(String, name, args[1]);
9813 CONVERT_CHECKED(Smi, flag, args[2]);
9814 CONVERT_CHECKED(JSFunction, fun, args[3]);
9815 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9816}
9817
9818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009819RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009820 ASSERT(args.length() == 3);
9821 CONVERT_CHECKED(JSObject, obj, args[0]);
9822 CONVERT_CHECKED(String, name, args[1]);
9823 CONVERT_CHECKED(Smi, flag, args[2]);
9824 return obj->LookupAccessor(name, flag->value() == 0);
9825}
9826
9827
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009828#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009829RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009830 ASSERT(args.length() == 0);
9831 return Execution::DebugBreakHelper();
9832}
9833
9834
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009835// Helper functions for wrapping and unwrapping stack frame ids.
9836static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009837 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009838 return Smi::FromInt(id >> 2);
9839}
9840
9841
9842static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9843 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9844}
9845
9846
9847// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009848// args[0]: debug event listener function to set or null or undefined for
9849// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009850// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009851RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009852 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009853 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9854 args[0]->IsUndefined() ||
9855 args[0]->IsNull());
9856 Handle<Object> callback = args.at<Object>(0);
9857 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009858 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009860 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009861}
9862
9863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009864RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009865 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009866 isolate->stack_guard()->DebugBreak();
9867 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009868}
9869
9870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009871static MaybeObject* DebugLookupResultValue(Heap* heap,
9872 Object* receiver,
9873 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009874 LookupResult* result,
9875 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009876 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009877 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009878 case NORMAL:
9879 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009880 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009881 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009882 }
9883 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009884 case FIELD:
9885 value =
9886 JSObject::cast(
9887 result->holder())->FastPropertyAt(result->GetFieldIndex());
9888 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009889 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009890 }
9891 return value;
9892 case CONSTANT_FUNCTION:
9893 return result->GetConstantFunction();
9894 case CALLBACKS: {
9895 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009896 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009897 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009898 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009899 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009900 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009901 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009902 maybe_value = heap->isolate()->pending_exception();
9903 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009904 if (caught_exception != NULL) {
9905 *caught_exception = true;
9906 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009907 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009908 }
9909 return value;
9910 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009911 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009912 }
9913 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009914 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009915 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009916 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009917 case CONSTANT_TRANSITION:
9918 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009919 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009920 default:
9921 UNREACHABLE();
9922 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009923 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009924 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009925}
9926
9927
ager@chromium.org32912102009-01-16 10:38:43 +00009928// Get debugger related details for an object property.
9929// args[0]: object holding property
9930// args[1]: name of the property
9931//
9932// The array returned contains the following information:
9933// 0: Property value
9934// 1: Property details
9935// 2: Property value is exception
9936// 3: Getter function if defined
9937// 4: Setter function if defined
9938// Items 2-4 are only filled if the property has either a getter or a setter
9939// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009940RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009941 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009942
9943 ASSERT(args.length() == 2);
9944
9945 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9946 CONVERT_ARG_CHECKED(String, name, 1);
9947
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009948 // Make sure to set the current context to the context before the debugger was
9949 // entered (if the debugger is entered). The reason for switching context here
9950 // is that for some property lookups (accessors and interceptors) callbacks
9951 // into the embedding application can occour, and the embedding application
9952 // could have the assumption that its own global context is the current
9953 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009954 SaveContext save(isolate);
9955 if (isolate->debug()->InDebugger()) {
9956 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009957 }
9958
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009959 // Skip the global proxy as it has no properties and always delegates to the
9960 // real global object.
9961 if (obj->IsJSGlobalProxy()) {
9962 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9963 }
9964
9965
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009966 // Check if the name is trivially convertible to an index and get the element
9967 // if so.
9968 uint32_t index;
9969 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009970 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009971 Object* element_or_char;
9972 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009973 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009974 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9975 return maybe_element_or_char;
9976 }
9977 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009978 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009979 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009980 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009981 }
9982
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009983 // Find the number of objects making up this.
9984 int length = LocalPrototypeChainLength(*obj);
9985
9986 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009987 Handle<JSObject> jsproto = obj;
9988 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009989 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009990 jsproto->LocalLookup(*name, &result);
9991 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009992 // LookupResult is not GC safe as it holds raw object pointers.
9993 // GC can happen later in this code so put the required fields into
9994 // local variables using handles when required for later use.
9995 PropertyType result_type = result.type();
9996 Handle<Object> result_callback_obj;
9997 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009998 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9999 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010000 }
10001 Smi* property_details = result.GetPropertyDetails().AsSmi();
10002 // DebugLookupResultValue can cause GC so details from LookupResult needs
10003 // to be copied to handles before this.
10004 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010005 Object* raw_value;
10006 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010007 DebugLookupResultValue(isolate->heap(), *obj, *name,
10008 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010009 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10010 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010011 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010012
10013 // If the callback object is a fixed array then it contains JavaScript
10014 // getter and/or setter.
10015 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10016 result_callback_obj->IsFixedArray();
10017 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010018 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010019 details->set(0, *value);
10020 details->set(1, property_details);
10021 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010022 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010023 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10024 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10025 }
10026
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010027 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010028 }
10029 if (i < length - 1) {
10030 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10031 }
10032 }
10033
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010034 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010035}
10036
10037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010038RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010039 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010040
10041 ASSERT(args.length() == 2);
10042
10043 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10044 CONVERT_ARG_CHECKED(String, name, 1);
10045
10046 LookupResult result;
10047 obj->Lookup(*name, &result);
10048 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010049 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010050 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010051 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010052}
10053
10054
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010055// Return the property type calculated from the property details.
10056// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010057RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010058 ASSERT(args.length() == 1);
10059 CONVERT_CHECKED(Smi, details, args[0]);
10060 PropertyType type = PropertyDetails(details).type();
10061 return Smi::FromInt(static_cast<int>(type));
10062}
10063
10064
10065// Return the property attribute calculated from the property details.
10066// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010067RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010068 ASSERT(args.length() == 1);
10069 CONVERT_CHECKED(Smi, details, args[0]);
10070 PropertyAttributes attributes = PropertyDetails(details).attributes();
10071 return Smi::FromInt(static_cast<int>(attributes));
10072}
10073
10074
10075// Return the property insertion index calculated from the property details.
10076// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010077RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010078 ASSERT(args.length() == 1);
10079 CONVERT_CHECKED(Smi, details, args[0]);
10080 int index = PropertyDetails(details).index();
10081 return Smi::FromInt(index);
10082}
10083
10084
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010085// Return property value from named interceptor.
10086// args[0]: object
10087// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010088RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010089 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010090 ASSERT(args.length() == 2);
10091 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10092 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10093 CONVERT_ARG_CHECKED(String, name, 1);
10094
10095 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010096 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010097}
10098
10099
10100// Return element value from indexed interceptor.
10101// args[0]: object
10102// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010103RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010104 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010105 ASSERT(args.length() == 2);
10106 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10107 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10108 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10109
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010110 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010111}
10112
10113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010114RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115 ASSERT(args.length() >= 1);
10116 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010117 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010118 if (isolate->debug()->break_id() == 0 ||
10119 break_id != isolate->debug()->break_id()) {
10120 return isolate->Throw(
10121 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010122 }
10123
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010124 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010125}
10126
10127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010128RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010129 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010130 ASSERT(args.length() == 1);
10131
10132 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010133 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010134 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10135 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010136 if (!maybe_result->ToObject(&result)) return maybe_result;
10137 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010138
10139 // Count all frames which are relevant to debugging stack trace.
10140 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010141 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010142 if (id == StackFrame::NO_ID) {
10143 // If there is no JavaScript stack frame count is 0.
10144 return Smi::FromInt(0);
10145 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010146
10147 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10148 n += it.frame()->GetInlineCount();
10149 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010150 return Smi::FromInt(n);
10151}
10152
10153
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010154class FrameInspector {
10155 public:
10156 FrameInspector(JavaScriptFrame* frame,
10157 int inlined_frame_index,
10158 Isolate* isolate)
10159 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10160 // Calculate the deoptimized frame.
10161 if (frame->is_optimized()) {
10162 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10163 frame, inlined_frame_index, isolate);
10164 }
10165 has_adapted_arguments_ = frame_->has_adapted_arguments();
10166 is_optimized_ = frame_->is_optimized();
10167 }
10168
10169 ~FrameInspector() {
10170 // Get rid of the calculated deoptimized frame if any.
10171 if (deoptimized_frame_ != NULL) {
10172 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10173 isolate_);
10174 }
10175 }
10176
10177 int GetParametersCount() {
10178 return is_optimized_
10179 ? deoptimized_frame_->parameters_count()
10180 : frame_->ComputeParametersCount();
10181 }
10182 int expression_count() { return deoptimized_frame_->expression_count(); }
10183 Object* GetFunction() {
10184 return is_optimized_
10185 ? deoptimized_frame_->GetFunction()
10186 : frame_->function();
10187 }
10188 Object* GetParameter(int index) {
10189 return is_optimized_
10190 ? deoptimized_frame_->GetParameter(index)
10191 : frame_->GetParameter(index);
10192 }
10193 Object* GetExpression(int index) {
10194 return is_optimized_
10195 ? deoptimized_frame_->GetExpression(index)
10196 : frame_->GetExpression(index);
10197 }
10198
10199 // To inspect all the provided arguments the frame might need to be
10200 // replaced with the arguments frame.
10201 void SetArgumentsFrame(JavaScriptFrame* frame) {
10202 ASSERT(has_adapted_arguments_);
10203 frame_ = frame;
10204 is_optimized_ = frame_->is_optimized();
10205 ASSERT(!is_optimized_);
10206 }
10207
10208 private:
10209 JavaScriptFrame* frame_;
10210 DeoptimizedFrameInfo* deoptimized_frame_;
10211 Isolate* isolate_;
10212 bool is_optimized_;
10213 bool has_adapted_arguments_;
10214
10215 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10216};
10217
10218
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010219static const int kFrameDetailsFrameIdIndex = 0;
10220static const int kFrameDetailsReceiverIndex = 1;
10221static const int kFrameDetailsFunctionIndex = 2;
10222static const int kFrameDetailsArgumentCountIndex = 3;
10223static const int kFrameDetailsLocalCountIndex = 4;
10224static const int kFrameDetailsSourcePositionIndex = 5;
10225static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010226static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010227static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010228static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010229
10230// Return an array with frame details
10231// args[0]: number: break id
10232// args[1]: number: frame index
10233//
10234// The array returned contains the following information:
10235// 0: Frame id
10236// 1: Receiver
10237// 2: Function
10238// 3: Argument count
10239// 4: Local count
10240// 5: Source position
10241// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010242// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010243// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010244// Arguments name, value
10245// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010246// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010247RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010248 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010249 ASSERT(args.length() == 2);
10250
10251 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010252 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010253 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10254 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010255 if (!maybe_check->ToObject(&check)) return maybe_check;
10256 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010257 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010258 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010259
10260 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010261 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010262 if (id == StackFrame::NO_ID) {
10263 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010264 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010265 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010266
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010267 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010268
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010269 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010270 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010271 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010272 if (index < count + it.frame()->GetInlineCount()) break;
10273 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010275 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010276
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010277 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010278 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010279 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010280 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010281 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010282
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010283 // Traverse the saved contexts chain to find the active context for the
10284 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010285 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010286 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010287 save = save->prev();
10288 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010289 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010290
10291 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010292 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010293
10294 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010295 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010296 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010297
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010298 // Check for constructor frame. Inlined frames cannot be construct calls.
10299 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010300 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010301 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010302
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010303 // Get scope info and read from it for local variable information.
10304 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010305 Handle<SharedFunctionInfo> shared(function->shared());
10306 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010307 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010308 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010310 // Get the locals names and values into a temporary array.
10311 //
10312 // TODO(1240907): Hide compiler-introduced stack variables
10313 // (e.g. .result)? For users of the debugger, they will probably be
10314 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010315 Handle<FixedArray> locals =
10316 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010317
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010318 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010319 int i = 0;
10320 for (; i < info.number_of_stack_slots(); ++i) {
10321 // Use the value from the stack.
10322 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010323 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010324 }
10325 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010326 // Get the context containing declarations.
10327 Handle<Context> context(
10328 Context::cast(it.frame()->context())->declaration_context());
10329 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010330 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010331 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010332 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010333 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010334 }
10335 }
10336
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010337 // Check whether this frame is positioned at return. If not top
10338 // frame or if the frame is optimized it cannot be at a return.
10339 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010340 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010341 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010342 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010343
10344 // If positioned just before return find the value to be returned and add it
10345 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010346 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010347 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010348 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010349 Address internal_frame_sp = NULL;
10350 while (!it2.done()) {
10351 if (it2.frame()->is_internal()) {
10352 internal_frame_sp = it2.frame()->sp();
10353 } else {
10354 if (it2.frame()->is_java_script()) {
10355 if (it2.frame()->id() == it.frame()->id()) {
10356 // The internal frame just before the JavaScript frame contains the
10357 // value to return on top. A debug break at return will create an
10358 // internal frame to store the return value (eax/rax/r0) before
10359 // entering the debug break exit frame.
10360 if (internal_frame_sp != NULL) {
10361 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010362 Handle<Object>(Memory::Object_at(internal_frame_sp),
10363 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010364 break;
10365 }
10366 }
10367 }
10368
10369 // Indicate that the previous frame was not an internal frame.
10370 internal_frame_sp = NULL;
10371 }
10372 it2.Advance();
10373 }
10374 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010375
10376 // Now advance to the arguments adapter frame (if any). It contains all
10377 // the provided parameters whereas the function frame always have the number
10378 // of arguments matching the functions parameters. The rest of the
10379 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010380 if (it.frame()->has_adapted_arguments()) {
10381 it.AdvanceToArgumentsFrame();
10382 frame_inspector.SetArgumentsFrame(it.frame());
10383 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010384
10385 // Find the number of arguments to fill. At least fill the number of
10386 // parameters for the function and fill more if more parameters are provided.
10387 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010388 if (argument_count < frame_inspector.GetParametersCount()) {
10389 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010390 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010391#ifdef DEBUG
10392 if (it.frame()->is_optimized()) {
10393 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10394 }
10395#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010396
10397 // Calculate the size of the result.
10398 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010399 2 * (argument_count + info.NumberOfLocals()) +
10400 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010401 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010402
10403 // Add the frame id.
10404 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10405
10406 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010407 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010408
10409 // Add the arguments count.
10410 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10411
10412 // Add the locals count
10413 details->set(kFrameDetailsLocalCountIndex,
10414 Smi::FromInt(info.NumberOfLocals()));
10415
10416 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010417 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010418 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10419 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010420 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010421 }
10422
10423 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010424 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010425
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010426 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010427 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010428
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010429 // Add flags to indicate information on whether this frame is
10430 // bit 0: invoked in the debugger context.
10431 // bit 1: optimized frame.
10432 // bit 2: inlined in optimized frame
10433 int flags = 0;
10434 if (*save->context() == *isolate->debug()->debug_context()) {
10435 flags |= 1 << 0;
10436 }
10437 if (it.frame()->is_optimized()) {
10438 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010439 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010440 }
10441 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010442
10443 // Fill the dynamic part.
10444 int details_index = kFrameDetailsFirstDynamicIndex;
10445
10446 // Add arguments name and value.
10447 for (int i = 0; i < argument_count; i++) {
10448 // Name of the argument.
10449 if (i < info.number_of_parameters()) {
10450 details->set(details_index++, *info.parameter_name(i));
10451 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010452 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010453 }
10454
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010455 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010456 if (i < it.frame()->ComputeParametersCount()) {
10457 // Get the value from the stack.
10458 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010459 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010460 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010461 }
10462 }
10463
10464 // Add locals name and value from the temporary copy from the function frame.
10465 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10466 details->set(details_index++, locals->get(i));
10467 }
10468
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010469 // Add the value being returned.
10470 if (at_return) {
10471 details->set(details_index++, *return_value);
10472 }
10473
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010474 // Add the receiver (same as in function frame).
10475 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10476 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010477 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010478 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10479 // If the receiver is not a JSObject and the function is not a
10480 // builtin or strict-mode we have hit an optimization where a
10481 // value object is not converted into a wrapped JS objects. To
10482 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010483 // by creating correct wrapper object based on the calling frame's
10484 // global context.
10485 it.Advance();
10486 Handle<Context> calling_frames_global_context(
10487 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010488 receiver =
10489 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010490 }
10491 details->set(kFrameDetailsReceiverIndex, *receiver);
10492
10493 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010494 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010495}
10496
10497
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010498// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010499static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010500 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010501 Handle<SerializedScopeInfo> serialized_scope_info,
10502 ScopeInfo<>& scope_info,
10503 Handle<Context> context,
10504 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010505 // Fill all context locals to the context extension.
10506 for (int i = Context::MIN_CONTEXT_SLOTS;
10507 i < scope_info.number_of_context_slots();
10508 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010509 int context_index = serialized_scope_info->ContextSlotIndex(
10510 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010511
whesse@chromium.org7b260152011-06-20 15:33:18 +000010512 RETURN_IF_EMPTY_HANDLE_VALUE(
10513 isolate,
10514 SetProperty(scope_object,
10515 scope_info.context_slot_name(i),
10516 Handle<Object>(context->get(context_index), isolate),
10517 NONE,
10518 kNonStrictMode),
10519 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010520 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010521
10522 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010523}
10524
10525
10526// Create a plain JSObject which materializes the local scope for the specified
10527// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010528static Handle<JSObject> MaterializeLocalScope(
10529 Isolate* isolate,
10530 JavaScriptFrame* frame,
10531 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010532 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010533 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010534 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10535 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010536 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010537
10538 // Allocate and initialize a JSObject with all the arguments, stack locals
10539 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010540 Handle<JSObject> local_scope =
10541 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010542
10543 // First fill all parameters.
10544 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010545 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010546 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010547 SetProperty(local_scope,
10548 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010549 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010550 NONE,
10551 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010552 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010553 }
10554
10555 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010556 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010557 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010558 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010559 SetProperty(local_scope,
10560 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010561 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010562 NONE,
10563 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010564 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010565 }
10566
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010567 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10568 // Third fill all context locals.
10569 Handle<Context> frame_context(Context::cast(frame->context()));
10570 Handle<Context> function_context(frame_context->declaration_context());
10571 if (!CopyContextLocalsToScopeObject(isolate,
10572 serialized_scope_info, scope_info,
10573 function_context, local_scope)) {
10574 return Handle<JSObject>();
10575 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010576
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010577 // Finally copy any properties from the function context extension.
10578 // These will be variables introduced by eval.
10579 if (function_context->closure() == *function) {
10580 if (function_context->has_extension() &&
10581 !function_context->IsGlobalContext()) {
10582 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10583 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10584 for (int i = 0; i < keys->length(); i++) {
10585 // Names of variables introduced by eval are strings.
10586 ASSERT(keys->get(i)->IsString());
10587 Handle<String> key(String::cast(keys->get(i)));
10588 RETURN_IF_EMPTY_HANDLE_VALUE(
10589 isolate,
10590 SetProperty(local_scope,
10591 key,
10592 GetProperty(ext, key),
10593 NONE,
10594 kNonStrictMode),
10595 Handle<JSObject>());
10596 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010597 }
10598 }
10599 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010600
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010601 return local_scope;
10602}
10603
10604
10605// Create a plain JSObject which materializes the closure content for the
10606// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10608 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010609 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010610
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010611 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010612 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10613 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010614
10615 // Allocate and initialize a JSObject with all the content of theis function
10616 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010617 Handle<JSObject> closure_scope =
10618 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010619
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010620 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010621 if (!CopyContextLocalsToScopeObject(isolate,
10622 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010623 context, closure_scope)) {
10624 return Handle<JSObject>();
10625 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010626
10627 // Finally copy any properties from the function context extension. This will
10628 // be variables introduced by eval.
10629 if (context->has_extension()) {
10630 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010631 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010632 for (int i = 0; i < keys->length(); i++) {
10633 // Names of variables introduced by eval are strings.
10634 ASSERT(keys->get(i)->IsString());
10635 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010636 RETURN_IF_EMPTY_HANDLE_VALUE(
10637 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010638 SetProperty(closure_scope,
10639 key,
10640 GetProperty(ext, key),
10641 NONE,
10642 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010643 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010644 }
10645 }
10646
10647 return closure_scope;
10648}
10649
10650
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010651// Create a plain JSObject which materializes the scope for the specified
10652// catch context.
10653static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10654 Handle<Context> context) {
10655 ASSERT(context->IsCatchContext());
10656 Handle<String> name(String::cast(context->extension()));
10657 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10658 Handle<JSObject> catch_scope =
10659 isolate->factory()->NewJSObject(isolate->object_function());
10660 RETURN_IF_EMPTY_HANDLE_VALUE(
10661 isolate,
10662 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10663 Handle<JSObject>());
10664 return catch_scope;
10665}
10666
10667
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010668// Create a plain JSObject which materializes the block scope for the specified
10669// block context.
10670static Handle<JSObject> MaterializeBlockScope(
10671 Isolate* isolate,
10672 Handle<Context> context) {
10673 ASSERT(context->IsBlockContext());
10674 Handle<SerializedScopeInfo> serialized_scope_info(
10675 SerializedScopeInfo::cast(context->extension()));
10676 ScopeInfo<> scope_info(*serialized_scope_info);
10677
10678 // Allocate and initialize a JSObject with all the arguments, stack locals
10679 // heap locals and extension properties of the debugged function.
10680 Handle<JSObject> block_scope =
10681 isolate->factory()->NewJSObject(isolate->object_function());
10682
10683 // Fill all context locals.
10684 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10685 if (!CopyContextLocalsToScopeObject(isolate,
10686 serialized_scope_info, scope_info,
10687 context, block_scope)) {
10688 return Handle<JSObject>();
10689 }
10690 }
10691
10692 return block_scope;
10693}
10694
10695
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010696// Iterate over the actual scopes visible from a stack frame. All scopes are
10697// backed by an actual context except the local scope, which is inserted
10698// "artifically" in the context chain.
10699class ScopeIterator {
10700 public:
10701 enum ScopeType {
10702 ScopeTypeGlobal = 0,
10703 ScopeTypeLocal,
10704 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010705 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010706 ScopeTypeCatch,
10707 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010708 };
10709
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010710 ScopeIterator(Isolate* isolate,
10711 JavaScriptFrame* frame,
10712 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010713 : isolate_(isolate),
10714 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010715 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010716 function_(JSFunction::cast(frame->function())),
10717 context_(Context::cast(frame->context())),
10718 local_done_(false),
10719 at_local_(false) {
10720
10721 // Check whether the first scope is actually a local scope.
10722 if (context_->IsGlobalContext()) {
10723 // If there is a stack slot for .result then this local scope has been
10724 // created for evaluating top level code and it is not a real local scope.
10725 // Checking for the existence of .result seems fragile, but the scope info
10726 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010727 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010728 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010729 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010730 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010731 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010732 } else if (context_->closure() != *function_) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010733 // The context_ is a block or with or catch block from the outer function.
10734 ASSERT(context_->IsWithContext() ||
10735 context_->IsCatchContext() ||
10736 context_->IsBlockContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010737 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010738 }
10739 }
10740
10741 // More scopes?
10742 bool Done() { return context_.is_null(); }
10743
10744 // Move to the next scope.
10745 void Next() {
10746 // If at a local scope mark the local scope as passed.
10747 if (at_local_) {
10748 at_local_ = false;
10749 local_done_ = true;
10750
10751 // If the current context is not associated with the local scope the
10752 // current context is the next real scope, so don't move to the next
10753 // context in this case.
10754 if (context_->closure() != *function_) {
10755 return;
10756 }
10757 }
10758
10759 // The global scope is always the last in the chain.
10760 if (context_->IsGlobalContext()) {
10761 context_ = Handle<Context>();
10762 return;
10763 }
10764
10765 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010766 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010767
10768 // If passing the local scope indicate that the current scope is now the
10769 // local scope.
10770 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010771 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010772 at_local_ = true;
10773 }
10774 }
10775
10776 // Return the type of the current scope.
10777 int Type() {
10778 if (at_local_) {
10779 return ScopeTypeLocal;
10780 }
10781 if (context_->IsGlobalContext()) {
10782 ASSERT(context_->global()->IsGlobalObject());
10783 return ScopeTypeGlobal;
10784 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010785 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010786 return ScopeTypeClosure;
10787 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010788 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010789 return ScopeTypeCatch;
10790 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010791 if (context_->IsBlockContext()) {
10792 return ScopeTypeBlock;
10793 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010794 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010795 return ScopeTypeWith;
10796 }
10797
10798 // Return the JavaScript object with the content of the current scope.
10799 Handle<JSObject> ScopeObject() {
10800 switch (Type()) {
10801 case ScopeIterator::ScopeTypeGlobal:
10802 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010803 case ScopeIterator::ScopeTypeLocal:
10804 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010805 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010806 case ScopeIterator::ScopeTypeWith:
10807 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010808 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10809 case ScopeIterator::ScopeTypeCatch:
10810 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010811 case ScopeIterator::ScopeTypeClosure:
10812 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010813 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010814 case ScopeIterator::ScopeTypeBlock:
10815 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010816 }
10817 UNREACHABLE();
10818 return Handle<JSObject>();
10819 }
10820
10821 // Return the context for this scope. For the local context there might not
10822 // be an actual context.
10823 Handle<Context> CurrentContext() {
10824 if (at_local_ && context_->closure() != *function_) {
10825 return Handle<Context>();
10826 }
10827 return context_;
10828 }
10829
10830#ifdef DEBUG
10831 // Debug print of the content of the current scope.
10832 void DebugPrint() {
10833 switch (Type()) {
10834 case ScopeIterator::ScopeTypeGlobal:
10835 PrintF("Global:\n");
10836 CurrentContext()->Print();
10837 break;
10838
10839 case ScopeIterator::ScopeTypeLocal: {
10840 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010841 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010842 scope_info.Print();
10843 if (!CurrentContext().is_null()) {
10844 CurrentContext()->Print();
10845 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010846 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010847 if (extension->IsJSContextExtensionObject()) {
10848 extension->Print();
10849 }
10850 }
10851 }
10852 break;
10853 }
10854
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010855 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010856 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010857 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010858 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010859
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010860 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010861 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010862 CurrentContext()->extension()->Print();
10863 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010864 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010865
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010866 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010867 PrintF("Closure:\n");
10868 CurrentContext()->Print();
10869 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010870 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010871 if (extension->IsJSContextExtensionObject()) {
10872 extension->Print();
10873 }
10874 }
10875 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010876
10877 default:
10878 UNREACHABLE();
10879 }
10880 PrintF("\n");
10881 }
10882#endif
10883
10884 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010885 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010886 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010887 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010888 Handle<JSFunction> function_;
10889 Handle<Context> context_;
10890 bool local_done_;
10891 bool at_local_;
10892
10893 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10894};
10895
10896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010897RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010898 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010899 ASSERT(args.length() == 2);
10900
10901 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010902 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010903 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10904 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010905 if (!maybe_check->ToObject(&check)) return maybe_check;
10906 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010907 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10908
10909 // Get the frame where the debugging is performed.
10910 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010911 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010912 JavaScriptFrame* frame = it.frame();
10913
10914 // Count the visible scopes.
10915 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010916 for (ScopeIterator it(isolate, frame, 0);
10917 !it.Done();
10918 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010919 n++;
10920 }
10921
10922 return Smi::FromInt(n);
10923}
10924
10925
10926static const int kScopeDetailsTypeIndex = 0;
10927static const int kScopeDetailsObjectIndex = 1;
10928static const int kScopeDetailsSize = 2;
10929
10930// Return an array with scope details
10931// args[0]: number: break id
10932// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010933// args[2]: number: inlined frame index
10934// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010935//
10936// The array returned contains the following information:
10937// 0: Scope type
10938// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010939RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010940 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010941 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010942
10943 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010944 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010945 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10946 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010947 if (!maybe_check->ToObject(&check)) return maybe_check;
10948 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010949 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010950 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
10951 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010952
10953 // Get the frame where the debugging is performed.
10954 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010955 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010956 JavaScriptFrame* frame = frame_it.frame();
10957
10958 // Find the requested scope.
10959 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010960 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010961 for (; !it.Done() && n < index; it.Next()) {
10962 n++;
10963 }
10964 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010965 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010966 }
10967
10968 // Calculate the size of the result.
10969 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010970 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010971
10972 // Fill in scope details.
10973 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010974 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010975 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010976 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010977
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010978 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010979}
10980
10981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010982RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010983 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010984 ASSERT(args.length() == 0);
10985
10986#ifdef DEBUG
10987 // Print the scopes for the top frame.
10988 StackFrameLocator locator;
10989 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010990 for (ScopeIterator it(isolate, frame, 0);
10991 !it.Done();
10992 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010993 it.DebugPrint();
10994 }
10995#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010996 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010997}
10998
10999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011000RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011001 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011002 ASSERT(args.length() == 1);
11003
11004 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011005 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011006 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11007 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011008 if (!maybe_result->ToObject(&result)) return maybe_result;
11009 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011010
11011 // Count all archived V8 threads.
11012 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011013 for (ThreadState* thread =
11014 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011015 thread != NULL;
11016 thread = thread->Next()) {
11017 n++;
11018 }
11019
11020 // Total number of threads is current thread and archived threads.
11021 return Smi::FromInt(n + 1);
11022}
11023
11024
11025static const int kThreadDetailsCurrentThreadIndex = 0;
11026static const int kThreadDetailsThreadIdIndex = 1;
11027static const int kThreadDetailsSize = 2;
11028
11029// Return an array with thread details
11030// args[0]: number: break id
11031// args[1]: number: thread index
11032//
11033// The array returned contains the following information:
11034// 0: Is current thread?
11035// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011036RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011037 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011038 ASSERT(args.length() == 2);
11039
11040 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011041 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011042 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11043 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011044 if (!maybe_check->ToObject(&check)) return maybe_check;
11045 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011046 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11047
11048 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011049 Handle<FixedArray> details =
11050 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011051
11052 // Thread index 0 is current thread.
11053 if (index == 0) {
11054 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011055 details->set(kThreadDetailsCurrentThreadIndex,
11056 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011057 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011058 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011059 } else {
11060 // Find the thread with the requested index.
11061 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011062 ThreadState* thread =
11063 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011064 while (index != n && thread != NULL) {
11065 thread = thread->Next();
11066 n++;
11067 }
11068 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011069 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011070 }
11071
11072 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011073 details->set(kThreadDetailsCurrentThreadIndex,
11074 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011075 details->set(kThreadDetailsThreadIdIndex,
11076 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011077 }
11078
11079 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011080 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011081}
11082
11083
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011084// Sets the disable break state
11085// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011086RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011087 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011088 ASSERT(args.length() == 1);
11089 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011090 isolate->debug()->set_disable_break(disable_break);
11091 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011092}
11093
11094
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011095RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011096 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011097 ASSERT(args.length() == 1);
11098
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011099 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11100 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011101 // Find the number of break points
11102 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011103 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011104 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011105 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011106 Handle<FixedArray>::cast(break_locations));
11107}
11108
11109
11110// Set a break point in a function
11111// args[0]: function
11112// args[1]: number: break source position (within the function source)
11113// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011114RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011115 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011116 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011117 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11118 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011119 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11120 RUNTIME_ASSERT(source_position >= 0);
11121 Handle<Object> break_point_object_arg = args.at<Object>(2);
11122
11123 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011124 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11125 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011126
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011127 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011128}
11129
11130
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011131Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11132 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011133 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011134 // Iterate the heap looking for SharedFunctionInfo generated from the
11135 // script. The inner most SharedFunctionInfo containing the source position
11136 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011137 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011138 // which is found is not compiled it is compiled and the heap is iterated
11139 // again as the compilation might create inner functions from the newly
11140 // compiled function and the actual requested break point might be in one of
11141 // these functions.
11142 bool done = false;
11143 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011144 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011145 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011146 while (!done) {
11147 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011148 for (HeapObject* obj = iterator.next();
11149 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011150 if (obj->IsSharedFunctionInfo()) {
11151 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11152 if (shared->script() == *script) {
11153 // If the SharedFunctionInfo found has the requested script data and
11154 // contains the source position it is a candidate.
11155 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000011156 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011157 start_position = shared->start_position();
11158 }
11159 if (start_position <= position &&
11160 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000011161 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011162 // candidate this is the new candidate.
11163 if (target.is_null()) {
11164 target_start_position = start_position;
11165 target = shared;
11166 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011167 if (target_start_position == start_position &&
11168 shared->end_position() == target->end_position()) {
11169 // If a top-level function contain only one function
11170 // declartion the source for the top-level and the function is
11171 // the same. In that case prefer the non top-level function.
11172 if (!shared->is_toplevel()) {
11173 target_start_position = start_position;
11174 target = shared;
11175 }
11176 } else if (target_start_position <= start_position &&
11177 shared->end_position() <= target->end_position()) {
11178 // This containment check includes equality as a function inside
11179 // a top-level function can share either start or end position
11180 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011181 target_start_position = start_position;
11182 target = shared;
11183 }
11184 }
11185 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011186 }
11187 }
11188 }
11189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011190 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011191 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011192 }
11193
11194 // If the candidate found is compiled we are done. NOTE: when lazy
11195 // compilation of inner functions is introduced some additional checking
11196 // needs to be done here to compile inner functions.
11197 done = target->is_compiled();
11198 if (!done) {
11199 // If the candidate is not compiled compile it to reveal any inner
11200 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011201 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011202 }
11203 }
11204
11205 return *target;
11206}
11207
11208
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011209// Changes the state of a break point in a script and returns source position
11210// where break point was set. NOTE: Regarding performance see the NOTE for
11211// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011212// args[0]: script to set break point in
11213// args[1]: number: break source position (within the script source)
11214// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011215RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011216 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011217 ASSERT(args.length() == 3);
11218 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11219 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11220 RUNTIME_ASSERT(source_position >= 0);
11221 Handle<Object> break_point_object_arg = args.at<Object>(2);
11222
11223 // Get the script from the script wrapper.
11224 RUNTIME_ASSERT(wrapper->value()->IsScript());
11225 Handle<Script> script(Script::cast(wrapper->value()));
11226
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011227 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011228 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011229 if (!result->IsUndefined()) {
11230 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11231 // Find position within function. The script position might be before the
11232 // source position of the first function.
11233 int position;
11234 if (shared->start_position() > source_position) {
11235 position = 0;
11236 } else {
11237 position = source_position - shared->start_position();
11238 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011239 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011240 position += shared->start_position();
11241 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011242 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011243 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011244}
11245
11246
11247// Clear a break point
11248// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011249RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011250 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011251 ASSERT(args.length() == 1);
11252 Handle<Object> break_point_object_arg = args.at<Object>(0);
11253
11254 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011255 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011256
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011257 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011258}
11259
11260
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011261// Change the state of break on exceptions.
11262// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11263// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011264RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011265 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011266 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011267 RUNTIME_ASSERT(args[0]->IsNumber());
11268 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011269
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011270 // If the number doesn't match an enum value, the ChangeBreakOnException
11271 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011272 ExceptionBreakType type =
11273 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011274 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011275 isolate->debug()->ChangeBreakOnException(type, enable);
11276 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011277}
11278
11279
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011280// Returns the state of break on exceptions
11281// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011282RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011283 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011284 ASSERT(args.length() == 1);
11285 RUNTIME_ASSERT(args[0]->IsNumber());
11286
11287 ExceptionBreakType type =
11288 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011289 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011290 return Smi::FromInt(result);
11291}
11292
11293
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011294// Prepare for stepping
11295// args[0]: break id for checking execution state
11296// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011297// args[2]: number of times to perform the step, for step out it is the number
11298// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011299RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011300 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011301 ASSERT(args.length() == 3);
11302 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011303 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011304 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11305 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011306 if (!maybe_check->ToObject(&check)) return maybe_check;
11307 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011308 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011309 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011310 }
11311
11312 // Get the step action and check validity.
11313 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11314 if (step_action != StepIn &&
11315 step_action != StepNext &&
11316 step_action != StepOut &&
11317 step_action != StepInMin &&
11318 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011319 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011320 }
11321
11322 // Get the number of steps.
11323 int step_count = NumberToInt32(args[2]);
11324 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011325 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011326 }
11327
ager@chromium.orga1645e22009-09-09 19:27:10 +000011328 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011329 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011330
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011331 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011332 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11333 step_count);
11334 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011335}
11336
11337
11338// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011339RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011340 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011341 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011342 isolate->debug()->ClearStepping();
11343 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011344}
11345
11346
11347// Creates a copy of the with context chain. The copy of the context chain is
11348// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011349static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011350 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011351 Handle<Context> current,
11352 Handle<Context> base) {
11353 // At the end of the chain. Return the base context to link to.
11354 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11355 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011356 }
11357
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011358 // Recursively copy the with and catch contexts.
11359 HandleScope scope(isolate);
11360 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011361 Handle<Context> new_previous =
11362 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011363 Handle<Context> new_current;
11364 if (current->IsCatchContext()) {
11365 Handle<String> name(String::cast(current->extension()));
11366 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11367 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011368 isolate->factory()->NewCatchContext(function,
11369 new_previous,
11370 name,
11371 thrown_object);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011372 } else if (current->IsBlockContext()) {
11373 Handle<SerializedScopeInfo> scope_info(
11374 SerializedScopeInfo::cast(current->extension()));
11375 new_current =
11376 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011377 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011378 ASSERT(current->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011379 Handle<JSObject> extension(JSObject::cast(current->extension()));
11380 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011381 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011382 }
11383 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011384}
11385
11386
11387// Helper function to find or create the arguments object for
11388// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011389static Handle<Object> GetArgumentsObject(Isolate* isolate,
11390 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011391 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011392 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011393 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011394 const ScopeInfo<>* sinfo,
11395 Handle<Context> function_context) {
11396 // Try to find the value of 'arguments' to pass as parameter. If it is not
11397 // found (that is the debugged function does not reference 'arguments' and
11398 // does not support eval) then create an 'arguments' object.
11399 int index;
11400 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011401 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011402 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011403 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011404 }
11405 }
11406
11407 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011408 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11409 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011410 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011411 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011412 }
11413 }
11414
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011415 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11416
11417 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011418 Handle<JSObject> arguments =
11419 isolate->factory()->NewArgumentsObject(function, length);
11420 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011421
11422 AssertNoAllocation no_gc;
11423 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011424 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011425 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011426 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011427 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011428 return arguments;
11429}
11430
11431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011432static const char kSourceStr[] =
11433 "(function(arguments,__source__){return eval(__source__);})";
11434
11435
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011436// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011437// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011438// extension part has all the parameters and locals of the function on the
11439// stack frame. A function which calls eval with the code to evaluate is then
11440// compiled in this context and called in this context. As this context
11441// replaces the context of the function on the stack frame a new (empty)
11442// function is created as well to be used as the closure for the context.
11443// This function and the context acts as replacements for the function on the
11444// stack frame presenting the same view of the values of parameters and
11445// local variables as if the piece of JavaScript was evaluated at the point
11446// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011447RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011448 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011449
11450 // Check the execution state and decode arguments frame and source to be
11451 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011452 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011453 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011454 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11455 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011456 if (!maybe_check_result->ToObject(&check_result)) {
11457 return maybe_check_result;
11458 }
11459 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011460 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011461 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11462 CONVERT_ARG_CHECKED(String, source, 3);
11463 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11464 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011465
11466 // Handle the processing of break.
11467 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011468
11469 // Get the frame where the debugging is performed.
11470 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011471 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011472 JavaScriptFrame* frame = it.frame();
11473 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011474 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011475 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011476
11477 // Traverse the saved contexts chain to find the active context for the
11478 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011479 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011480 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011481 save = save->prev();
11482 }
11483 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011484 SaveContext savex(isolate);
11485 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011486
11487 // Create the (empty) function replacing the function on the stack frame for
11488 // the purpose of evaluating in the context created below. It is important
11489 // that this function does not describe any parameters and local variables
11490 // in the context. If it does then this will cause problems with the lookup
11491 // in Context::Lookup, where context slots for parameters and local variables
11492 // are looked at before the extension object.
11493 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011494 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11495 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011496 go_between->set_context(function->context());
11497#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011498 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011499 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11500 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11501#endif
11502
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011503 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011504 Handle<JSObject> local_scope = MaterializeLocalScope(
11505 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011506 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011507
11508 // Allocate a new context for the debug evaluation and set the extension
11509 // object build.
11510 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011511 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11512 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011513 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011514 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011515 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011516 Handle<Context> function_context;
11517 // Get the function's context if it has one.
11518 if (scope_info->HasHeapAllocatedLocals()) {
11519 function_context = Handle<Context>(frame_context->declaration_context());
11520 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011521 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011522
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011523 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011524 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011525 context =
11526 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011527 }
11528
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011529 // Wrap the evaluation statement in a new function compiled in the newly
11530 // created context. The function has one parameter which has to be called
11531 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011532 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011533 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011534
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011535 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011536 isolate->factory()->NewStringFromAscii(
11537 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011538
11539 // Currently, the eval code will be executed in non-strict mode,
11540 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011541 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011542 Compiler::CompileEval(function_source,
11543 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011544 context->IsGlobalContext(),
11545 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011546 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011547 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011548 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011549
11550 // Invoke the result of the compilation to get the evaluation function.
11551 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011552 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011553 Handle<Object> evaluation_function =
11554 Execution::Call(compiled_function, receiver, 0, NULL,
11555 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011556 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011557
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011558 Handle<Object> arguments = GetArgumentsObject(isolate,
11559 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011560 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011561 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011562
11563 // Invoke the evaluation function and return the result.
11564 const int argc = 2;
11565 Object** argv[argc] = { arguments.location(),
11566 Handle<Object>::cast(source).location() };
11567 Handle<Object> result =
11568 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11569 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011570 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011571
11572 // Skip the global proxy as it has no properties and always delegates to the
11573 // real global object.
11574 if (result->IsJSGlobalProxy()) {
11575 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11576 }
11577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011578 return *result;
11579}
11580
11581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011582RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011583 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011584
11585 // Check the execution state and decode arguments frame and source to be
11586 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011587 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011588 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011589 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11590 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011591 if (!maybe_check_result->ToObject(&check_result)) {
11592 return maybe_check_result;
11593 }
11594 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011595 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011596 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011597 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011598
11599 // Handle the processing of break.
11600 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011601
11602 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011603 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011604 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011605 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011606 top = top->prev();
11607 }
11608 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011609 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011610 }
11611
11612 // Get the global context now set to the top context from before the
11613 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011615
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011616 bool is_global = true;
11617
11618 if (additional_context->IsJSObject()) {
11619 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011620 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11621 isolate->factory()->empty_string(),
11622 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011623 go_between->set_context(*context);
11624 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 isolate->factory()->NewFunctionContext(
11626 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011627 context->set_extension(JSObject::cast(*additional_context));
11628 is_global = false;
11629 }
11630
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011631 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011632 // Currently, the eval code will be executed in non-strict mode,
11633 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011634 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011635 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011636 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011637 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011638 Handle<JSFunction>(
11639 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11640 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011641
11642 // Invoke the result of the compilation to get the evaluation function.
11643 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011644 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011645 Handle<Object> result =
11646 Execution::Call(compiled_function, receiver, 0, NULL,
11647 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011648 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011649 return *result;
11650}
11651
11652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011653RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011654 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011655 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011656
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011657 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011658 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011659
11660 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011661 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011662 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11663 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11664 // because using
11665 // instances->set(i, *GetScriptWrapper(script))
11666 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11667 // already have deferenced the instances handle.
11668 Handle<JSValue> wrapper = GetScriptWrapper(script);
11669 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011670 }
11671
11672 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011673 Handle<JSObject> result =
11674 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011675 Handle<JSArray>::cast(result)->SetContent(*instances);
11676 return *result;
11677}
11678
11679
11680// Helper function used by Runtime_DebugReferencedBy below.
11681static int DebugReferencedBy(JSObject* target,
11682 Object* instance_filter, int max_references,
11683 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011684 JSFunction* arguments_function) {
11685 NoHandleAllocation ha;
11686 AssertNoAllocation no_alloc;
11687
11688 // Iterate the heap.
11689 int count = 0;
11690 JSObject* last = NULL;
11691 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011692 HeapObject* heap_obj = NULL;
11693 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011694 (max_references == 0 || count < max_references)) {
11695 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011696 if (heap_obj->IsJSObject()) {
11697 // Skip context extension objects and argument arrays as these are
11698 // checked in the context of functions using them.
11699 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011700 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011701 obj->map()->constructor() == arguments_function) {
11702 continue;
11703 }
11704
11705 // Check if the JS object has a reference to the object looked for.
11706 if (obj->ReferencesObject(target)) {
11707 // Check instance filter if supplied. This is normally used to avoid
11708 // references from mirror objects (see Runtime_IsInPrototypeChain).
11709 if (!instance_filter->IsUndefined()) {
11710 Object* V = obj;
11711 while (true) {
11712 Object* prototype = V->GetPrototype();
11713 if (prototype->IsNull()) {
11714 break;
11715 }
11716 if (instance_filter == prototype) {
11717 obj = NULL; // Don't add this object.
11718 break;
11719 }
11720 V = prototype;
11721 }
11722 }
11723
11724 if (obj != NULL) {
11725 // Valid reference found add to instance array if supplied an update
11726 // count.
11727 if (instances != NULL && count < instances_size) {
11728 instances->set(count, obj);
11729 }
11730 last = obj;
11731 count++;
11732 }
11733 }
11734 }
11735 }
11736
11737 // Check for circular reference only. This can happen when the object is only
11738 // referenced from mirrors and has a circular reference in which case the
11739 // object is not really alive and would have been garbage collected if not
11740 // referenced from the mirror.
11741 if (count == 1 && last == target) {
11742 count = 0;
11743 }
11744
11745 // Return the number of referencing objects found.
11746 return count;
11747}
11748
11749
11750// Scan the heap for objects with direct references to an object
11751// args[0]: the object to find references to
11752// args[1]: constructor function for instances to exclude (Mirror)
11753// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011754RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011755 ASSERT(args.length() == 3);
11756
11757 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011758 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011759
11760 // Check parameters.
11761 CONVERT_CHECKED(JSObject, target, args[0]);
11762 Object* instance_filter = args[1];
11763 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11764 instance_filter->IsJSObject());
11765 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11766 RUNTIME_ASSERT(max_references >= 0);
11767
11768 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011769 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011770 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011771 JSFunction* arguments_function =
11772 JSFunction::cast(arguments_boilerplate->map()->constructor());
11773
11774 // Get the number of referencing objects.
11775 int count;
11776 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011777 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011778
11779 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011780 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011781 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011782 if (!maybe_object->ToObject(&object)) return maybe_object;
11783 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784 FixedArray* instances = FixedArray::cast(object);
11785
11786 // Fill the referencing objects.
11787 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011788 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011789
11790 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011791 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011792 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11793 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011794 if (!maybe_result->ToObject(&result)) return maybe_result;
11795 }
11796 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797 return result;
11798}
11799
11800
11801// Helper function used by Runtime_DebugConstructedBy below.
11802static int DebugConstructedBy(JSFunction* constructor, int max_references,
11803 FixedArray* instances, int instances_size) {
11804 AssertNoAllocation no_alloc;
11805
11806 // Iterate the heap.
11807 int count = 0;
11808 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011809 HeapObject* heap_obj = NULL;
11810 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011811 (max_references == 0 || count < max_references)) {
11812 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011813 if (heap_obj->IsJSObject()) {
11814 JSObject* obj = JSObject::cast(heap_obj);
11815 if (obj->map()->constructor() == constructor) {
11816 // Valid reference found add to instance array if supplied an update
11817 // count.
11818 if (instances != NULL && count < instances_size) {
11819 instances->set(count, obj);
11820 }
11821 count++;
11822 }
11823 }
11824 }
11825
11826 // Return the number of referencing objects found.
11827 return count;
11828}
11829
11830
11831// Scan the heap for objects constructed by a specific function.
11832// args[0]: the constructor to find instances of
11833// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011834RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011835 ASSERT(args.length() == 2);
11836
11837 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011838 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011839
11840 // Check parameters.
11841 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11842 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11843 RUNTIME_ASSERT(max_references >= 0);
11844
11845 // Get the number of referencing objects.
11846 int count;
11847 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11848
11849 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011850 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011851 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011852 if (!maybe_object->ToObject(&object)) return maybe_object;
11853 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011854 FixedArray* instances = FixedArray::cast(object);
11855
11856 // Fill the referencing objects.
11857 count = DebugConstructedBy(constructor, max_references, instances, count);
11858
11859 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011860 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011861 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11862 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011863 if (!maybe_result->ToObject(&result)) return maybe_result;
11864 }
11865 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011866 return result;
11867}
11868
11869
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011870// Find the effective prototype object as returned by __proto__.
11871// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011872RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011873 ASSERT(args.length() == 1);
11874
11875 CONVERT_CHECKED(JSObject, obj, args[0]);
11876
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011877 // Use the __proto__ accessor.
11878 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011879}
11880
11881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011882RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011883 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011884 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011885 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011886}
11887
11888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011889RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011890#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011891 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011892 ASSERT(args.length() == 1);
11893 // Get the function and make sure it is compiled.
11894 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011895 Handle<SharedFunctionInfo> shared(func->shared());
11896 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011897 return Failure::Exception();
11898 }
11899 func->code()->PrintLn();
11900#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011901 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011902}
ager@chromium.org9085a012009-05-11 19:22:57 +000011903
11904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011905RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011906#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011907 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011908 ASSERT(args.length() == 1);
11909 // Get the function and make sure it is compiled.
11910 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011911 Handle<SharedFunctionInfo> shared(func->shared());
11912 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011913 return Failure::Exception();
11914 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011915 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011916#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011917 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011918}
11919
11920
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011921RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011922 NoHandleAllocation ha;
11923 ASSERT(args.length() == 1);
11924
11925 CONVERT_CHECKED(JSFunction, f, args[0]);
11926 return f->shared()->inferred_name();
11927}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011928
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011929
11930static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011931 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011932 AssertNoAllocation no_allocations;
11933
11934 int counter = 0;
11935 int buffer_size = buffer->length();
11936 HeapIterator iterator;
11937 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11938 ASSERT(obj != NULL);
11939 if (!obj->IsSharedFunctionInfo()) {
11940 continue;
11941 }
11942 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11943 if (shared->script() != script) {
11944 continue;
11945 }
11946 if (counter < buffer_size) {
11947 buffer->set(counter, shared);
11948 }
11949 counter++;
11950 }
11951 return counter;
11952}
11953
11954// For a script finds all SharedFunctionInfo's in the heap that points
11955// to this script. Returns JSArray of SharedFunctionInfo wrapped
11956// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011957RUNTIME_FUNCTION(MaybeObject*,
11958 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011959 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011960 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011961 CONVERT_CHECKED(JSValue, script_value, args[0]);
11962
11963 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11964
11965 const int kBufferSize = 32;
11966
11967 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011968 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011969 int number = FindSharedFunctionInfosForScript(*script, *array);
11970 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011971 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011972 FindSharedFunctionInfosForScript(*script, *array);
11973 }
11974
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011975 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011976 result->set_length(Smi::FromInt(number));
11977
11978 LiveEdit::WrapSharedFunctionInfos(result);
11979
11980 return *result;
11981}
11982
11983// For a script calculates compilation information about all its functions.
11984// The script source is explicitly specified by the second argument.
11985// The source of the actual script is not used, however it is important that
11986// all generated code keeps references to this particular instance of script.
11987// Returns a JSArray of compilation infos. The array is ordered so that
11988// each function with all its descendant is always stored in a continues range
11989// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011990RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011991 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011992 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011993 CONVERT_CHECKED(JSValue, script, args[0]);
11994 CONVERT_ARG_CHECKED(String, source, 1);
11995 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11996
11997 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11998
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011999 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012000 return Failure::Exception();
12001 }
12002
12003 return result;
12004}
12005
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012006// Changes the source of the script to a new_source.
12007// If old_script_name is provided (i.e. is a String), also creates a copy of
12008// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012009RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012010 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012011 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012012 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12013 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012014 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012015
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012016 CONVERT_CHECKED(Script, original_script_pointer,
12017 original_script_value->value());
12018 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012019
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012020 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12021 new_source,
12022 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012023
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012024 if (old_script->IsScript()) {
12025 Handle<Script> script_handle(Script::cast(old_script));
12026 return *(GetScriptWrapper(script_handle));
12027 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012028 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012029 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012030}
12031
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012032
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012033RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012034 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012035 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012036 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12037 return LiveEdit::FunctionSourceUpdated(shared_info);
12038}
12039
12040
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012041// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012042RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012043 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012044 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012045 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12046 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12047
ager@chromium.orgac091b72010-05-05 07:34:42 +000012048 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012049}
12050
12051// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012052RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012053 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012054 HandleScope scope(isolate);
12055 Handle<Object> function_object(args[0], isolate);
12056 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012057
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012058 if (function_object->IsJSValue()) {
12059 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12060 if (script_object->IsJSValue()) {
12061 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012062 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012063 }
12064
12065 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12066 } else {
12067 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12068 // and we check it in this function.
12069 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012070
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012071 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012072}
12073
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012074
12075// In a code of a parent function replaces original function as embedded object
12076// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012077RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012078 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012079 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012080
12081 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12082 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12083 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12084
12085 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12086 subst_wrapper);
12087
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012088 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012089}
12090
12091
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012092// Updates positions of a shared function info (first parameter) according
12093// to script source change. Text change is described in second parameter as
12094// array of groups of 3 numbers:
12095// (change_begin, change_end, change_end_new_position).
12096// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012097RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012098 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012099 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012100 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12101 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12102
ager@chromium.orgac091b72010-05-05 07:34:42 +000012103 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012104}
12105
12106
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012107// For array of SharedFunctionInfo's (each wrapped in JSValue)
12108// checks that none of them have activations on stacks (of any thread).
12109// Returns array of the same length with corresponding results of
12110// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012111RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012112 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012113 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012114 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012115 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012116
ager@chromium.org357bf652010-04-12 11:30:10 +000012117 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012118}
12119
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012120// Compares 2 strings line-by-line, then token-wise and returns diff in form
12121// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12122// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012123RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012124 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012125 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012126 CONVERT_ARG_CHECKED(String, s1, 0);
12127 CONVERT_ARG_CHECKED(String, s2, 1);
12128
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012129 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012130}
12131
12132
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012133// A testing entry. Returns statement position which is the closest to
12134// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012135RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012136 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012137 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012138 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12139 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012141 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012142
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012143 if (code->kind() != Code::FUNCTION &&
12144 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012145 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012146 }
12147
12148 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012149 int closest_pc = 0;
12150 int distance = kMaxInt;
12151 while (!it.done()) {
12152 int statement_position = static_cast<int>(it.rinfo()->data());
12153 // Check if this break point is closer that what was previously found.
12154 if (source_position <= statement_position &&
12155 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012156 closest_pc =
12157 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012158 distance = statement_position - source_position;
12159 // Check whether we can't get any closer.
12160 if (distance == 0) break;
12161 }
12162 it.next();
12163 }
12164
12165 return Smi::FromInt(closest_pc);
12166}
12167
12168
ager@chromium.org357bf652010-04-12 11:30:10 +000012169// Calls specified function with or without entering the debugger.
12170// This is used in unit tests to run code as if debugger is entered or simply
12171// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012172RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012173 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012174 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012175 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12176 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12177
12178 Handle<Object> result;
12179 bool pending_exception;
12180 {
12181 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012182 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012183 &pending_exception);
12184 } else {
12185 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012186 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012187 &pending_exception);
12188 }
12189 }
12190 if (!pending_exception) {
12191 return *result;
12192 } else {
12193 return Failure::Exception();
12194 }
12195}
12196
12197
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012198// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012199RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012200 CONVERT_CHECKED(String, arg, args[0]);
12201 SmartPointer<char> flags =
12202 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12203 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012204 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012205}
12206
12207
12208// Performs a GC.
12209// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012210RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012211 isolate->heap()->CollectAllGarbage(true);
12212 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012213}
12214
12215
12216// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012217RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012218 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012219 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012220 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012221 }
12222 return Smi::FromInt(usage);
12223}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012224
12225
12226// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012227RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012228#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012229 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012230#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012231 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012232#endif
12233}
12234
12235
12236// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012237RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012238#ifdef LIVE_OBJECT_LIST
12239 return LiveObjectList::Capture();
12240#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012241 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012242#endif
12243}
12244
12245
12246// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012247RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012248#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012249 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012250 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012251 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012252#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012253 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012254#endif
12255}
12256
12257
12258// Generates the response to a debugger request for a dump of the objects
12259// contained in the difference between the captured live object lists
12260// specified by id1 and id2.
12261// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12262// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012263RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012264#ifdef LIVE_OBJECT_LIST
12265 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012266 CONVERT_SMI_ARG_CHECKED(id1, 0);
12267 CONVERT_SMI_ARG_CHECKED(id2, 1);
12268 CONVERT_SMI_ARG_CHECKED(start, 2);
12269 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012270 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12271 EnterDebugger enter_debugger;
12272 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12273#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012274 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012275#endif
12276}
12277
12278
12279// Gets the specified object as requested by the debugger.
12280// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012281RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012282#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012283 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012284 Object* result = LiveObjectList::GetObj(obj_id);
12285 return result;
12286#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012287 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012288#endif
12289}
12290
12291
12292// Gets the obj id for the specified address if valid.
12293// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012294RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012295#ifdef LIVE_OBJECT_LIST
12296 HandleScope scope;
12297 CONVERT_ARG_CHECKED(String, address, 0);
12298 Object* result = LiveObjectList::GetObjId(address);
12299 return result;
12300#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012301 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012302#endif
12303}
12304
12305
12306// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012307RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012308#ifdef LIVE_OBJECT_LIST
12309 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012310 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012311 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12312 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12313 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12314 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12315 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12316
12317 Handle<JSObject> instance_filter;
12318 if (args[1]->IsJSObject()) {
12319 instance_filter = args.at<JSObject>(1);
12320 }
12321 bool verbose = false;
12322 if (args[2]->IsBoolean()) {
12323 verbose = args[2]->IsTrue();
12324 }
12325 int start = 0;
12326 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012327 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012328 }
12329 int limit = Smi::kMaxValue;
12330 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012331 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012332 }
12333
12334 return LiveObjectList::GetObjRetainers(obj_id,
12335 instance_filter,
12336 verbose,
12337 start,
12338 limit,
12339 filter_obj);
12340#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012341 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012342#endif
12343}
12344
12345
12346// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012347RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012348#ifdef LIVE_OBJECT_LIST
12349 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012350 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12351 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012352 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12353
12354 Handle<JSObject> instance_filter;
12355 if (args[2]->IsJSObject()) {
12356 instance_filter = args.at<JSObject>(2);
12357 }
12358
12359 Object* result =
12360 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12361 return result;
12362#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012363 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012364#endif
12365}
12366
12367
12368// Generates the response to a debugger request for a list of all
12369// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012370RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012371#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012372 CONVERT_SMI_ARG_CHECKED(start, 0);
12373 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012374 return LiveObjectList::Info(start, count);
12375#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012376 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012377#endif
12378}
12379
12380
12381// Gets a dump of the specified object as requested by the debugger.
12382// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012383RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012384#ifdef LIVE_OBJECT_LIST
12385 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012386 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012387 Object* result = LiveObjectList::PrintObj(obj_id);
12388 return result;
12389#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012390 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012391#endif
12392}
12393
12394
12395// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012396RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012397#ifdef LIVE_OBJECT_LIST
12398 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012399 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012400#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012401 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012402#endif
12403}
12404
12405
12406// Generates the response to a debugger request for a summary of the types
12407// of objects in the difference between the captured live object lists
12408// specified by id1 and id2.
12409// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12410// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012411RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012412#ifdef LIVE_OBJECT_LIST
12413 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012414 CONVERT_SMI_ARG_CHECKED(id1, 0);
12415 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012416 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12417
12418 EnterDebugger enter_debugger;
12419 return LiveObjectList::Summarize(id1, id2, filter_obj);
12420#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012421 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012422#endif
12423}
12424
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012425#endif // ENABLE_DEBUGGER_SUPPORT
12426
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012427
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012428RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012429 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012430 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012431 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012432}
12433
12434
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012435RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012436 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012437 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012438 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012439}
12440
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012441
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012442// Finds the script object from the script data. NOTE: This operation uses
12443// heap traversal to find the function generated for the source position
12444// for the requested break point. For lazily compiled functions several heap
12445// traversals might be required rendering this operation as a rather slow
12446// operation. However for setting break points which is normally done through
12447// some kind of user interaction the performance is not crucial.
12448static Handle<Object> Runtime_GetScriptFromScriptName(
12449 Handle<String> script_name) {
12450 // Scan the heap for Script objects to find the script with the requested
12451 // script data.
12452 Handle<Script> script;
12453 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012454 HeapObject* obj = NULL;
12455 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012456 // If a script is found check if it has the script data requested.
12457 if (obj->IsScript()) {
12458 if (Script::cast(obj)->name()->IsString()) {
12459 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12460 script = Handle<Script>(Script::cast(obj));
12461 }
12462 }
12463 }
12464 }
12465
12466 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012467 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012468
12469 // Return the script found.
12470 return GetScriptWrapper(script);
12471}
12472
12473
12474// Get the script object from script data. NOTE: Regarding performance
12475// see the NOTE for GetScriptFromScriptData.
12476// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012477RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012478 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012479
12480 ASSERT(args.length() == 1);
12481
12482 CONVERT_CHECKED(String, script_name, args[0]);
12483
12484 // Find the requested script.
12485 Handle<Object> result =
12486 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12487 return *result;
12488}
12489
12490
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012491// Determines whether the given stack frame should be displayed in
12492// a stack trace. The caller is the error constructor that asked
12493// for the stack trace to be collected. The first time a construct
12494// call to this function is encountered it is skipped. The seen_caller
12495// in/out parameter is used to remember if the caller has been seen
12496// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012497static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12498 Object* caller,
12499 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012500 // Only display JS frames.
12501 if (!raw_frame->is_java_script())
12502 return false;
12503 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12504 Object* raw_fun = frame->function();
12505 // Not sure when this can happen but skip it just in case.
12506 if (!raw_fun->IsJSFunction())
12507 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012508 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012509 *seen_caller = true;
12510 return false;
12511 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012512 // Skip all frames until we've seen the caller.
12513 if (!(*seen_caller)) return false;
12514 // Also, skip the most obvious builtin calls. We recognize builtins
12515 // as (1) functions called with the builtins object as the receiver and
12516 // as (2) functions from native scripts called with undefined as the
12517 // receiver (direct calls to helper functions in the builtins
12518 // code). Some builtin calls (such as Number.ADD which is invoked
12519 // using 'call') are very difficult to recognize so we're leaving
12520 // them in for now.
12521 if (frame->receiver()->IsJSBuiltinsObject()) {
12522 return false;
12523 }
12524 JSFunction* fun = JSFunction::cast(raw_fun);
12525 Object* raw_script = fun->shared()->script();
12526 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12527 int script_type = Script::cast(raw_script)->type()->value();
12528 return script_type != Script::TYPE_NATIVE;
12529 }
12530 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012531}
12532
12533
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012534// Collect the raw data for a stack trace. Returns an array of 4
12535// element segments each containing a receiver, function, code and
12536// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012537RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012538 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012539 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012540 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12541
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012542 HandleScope scope(isolate);
12543 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012544
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012545 limit = Max(limit, 0); // Ensure that limit is not negative.
12546 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012547 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012548 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012549
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012550 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012551 // If the caller parameter is a function we skip frames until we're
12552 // under it before starting to collect.
12553 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012554 int cursor = 0;
12555 int frames_seen = 0;
12556 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012557 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012558 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012559 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012560 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012561 // Set initial size to the maximum inlining level + 1 for the outermost
12562 // function.
12563 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012564 frame->Summarize(&frames);
12565 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012566 if (cursor + 4 > elements->length()) {
12567 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12568 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012569 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012570 for (int i = 0; i < cursor; i++) {
12571 new_elements->set(i, elements->get(i));
12572 }
12573 elements = new_elements;
12574 }
12575 ASSERT(cursor + 4 <= elements->length());
12576
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012577 Handle<Object> recv = frames[i].receiver();
12578 Handle<JSFunction> fun = frames[i].function();
12579 Handle<Code> code = frames[i].code();
12580 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012581 elements->set(cursor++, *recv);
12582 elements->set(cursor++, *fun);
12583 elements->set(cursor++, *code);
12584 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012585 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012586 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012587 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012589 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012590 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012591 return *result;
12592}
12593
12594
ager@chromium.org3811b432009-10-28 14:53:37 +000012595// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012596RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012597 ASSERT_EQ(args.length(), 0);
12598
12599 NoHandleAllocation ha;
12600
12601 const char* version_string = v8::V8::GetVersion();
12602
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012603 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12604 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012605}
12606
12607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012608RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012609 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012610 OS::PrintError("abort: %s\n",
12611 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012612 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012613 OS::Abort();
12614 UNREACHABLE();
12615 return NULL;
12616}
12617
12618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012619RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012620 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012621 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012622 Object* key = args[1];
12623
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012624 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012625 Object* o = cache->get(finger_index);
12626 if (o == key) {
12627 // The fastest case: hit the same place again.
12628 return cache->get(finger_index + 1);
12629 }
12630
12631 for (int i = finger_index - 2;
12632 i >= JSFunctionResultCache::kEntriesIndex;
12633 i -= 2) {
12634 o = cache->get(i);
12635 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012636 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012637 return cache->get(i + 1);
12638 }
12639 }
12640
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012641 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012642 ASSERT(size <= cache->length());
12643
12644 for (int i = size - 2; i > finger_index; i -= 2) {
12645 o = cache->get(i);
12646 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012647 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012648 return cache->get(i + 1);
12649 }
12650 }
12651
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012652 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012653 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012654
12655 Handle<JSFunctionResultCache> cache_handle(cache);
12656 Handle<Object> key_handle(key);
12657 Handle<Object> value;
12658 {
12659 Handle<JSFunction> factory(JSFunction::cast(
12660 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12661 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012662 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012663 // This handle is nor shared, nor used later, so it's safe.
12664 Object** argv[] = { key_handle.location() };
12665 bool pending_exception = false;
12666 value = Execution::Call(factory,
12667 receiver,
12668 1,
12669 argv,
12670 &pending_exception);
12671 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012672 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012673
12674#ifdef DEBUG
12675 cache_handle->JSFunctionResultCacheVerify();
12676#endif
12677
12678 // Function invocation may have cleared the cache. Reread all the data.
12679 finger_index = cache_handle->finger_index();
12680 size = cache_handle->size();
12681
12682 // If we have spare room, put new data into it, otherwise evict post finger
12683 // entry which is likely to be the least recently used.
12684 int index = -1;
12685 if (size < cache_handle->length()) {
12686 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12687 index = size;
12688 } else {
12689 index = finger_index + JSFunctionResultCache::kEntrySize;
12690 if (index == cache_handle->length()) {
12691 index = JSFunctionResultCache::kEntriesIndex;
12692 }
12693 }
12694
12695 ASSERT(index % 2 == 0);
12696 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12697 ASSERT(index < cache_handle->length());
12698
12699 cache_handle->set(index, *key_handle);
12700 cache_handle->set(index + 1, *value);
12701 cache_handle->set_finger_index(index);
12702
12703#ifdef DEBUG
12704 cache_handle->JSFunctionResultCacheVerify();
12705#endif
12706
12707 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012708}
12709
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012710
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012711RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012712 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012713 CONVERT_ARG_CHECKED(String, type, 0);
12714 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012715 return *isolate->factory()->NewJSMessageObject(
12716 type,
12717 arguments,
12718 0,
12719 0,
12720 isolate->factory()->undefined_value(),
12721 isolate->factory()->undefined_value(),
12722 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012723}
12724
12725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012726RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012727 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12728 return message->type();
12729}
12730
12731
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012732RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012733 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12734 return message->arguments();
12735}
12736
12737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012738RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012739 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12740 return Smi::FromInt(message->start_position());
12741}
12742
12743
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012744RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012745 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12746 return message->script();
12747}
12748
12749
kasper.lund44510672008-07-25 07:37:58 +000012750#ifdef DEBUG
12751// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12752// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012753RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012754 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012755 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012756#define COUNT_ENTRY(Name, argc, ressize) + 1
12757 int entry_count = 0
12758 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12759 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12760 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12761#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012762 Factory* factory = isolate->factory();
12763 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012764 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012765 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012766#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012767 { \
12768 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012769 Handle<String> name; \
12770 /* Inline runtime functions have an underscore in front of the name. */ \
12771 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012772 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012773 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12774 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012775 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012776 Vector<const char>(#Name, StrLength(#Name))); \
12777 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012778 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012779 pair_elements->set(0, *name); \
12780 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012781 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012782 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012783 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012784 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012785 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012786 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012787 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012788 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012789#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012790 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012791 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012792 return *result;
12793}
kasper.lund44510672008-07-25 07:37:58 +000012794#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012795
12796
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012797RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012798 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012799 CONVERT_CHECKED(String, format, args[0]);
12800 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012801 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012802 LOGGER->LogRuntime(chars, elms);
12803 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012804}
12805
12806
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012807RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012808 UNREACHABLE(); // implemented as macro in the parser
12809 return NULL;
12810}
12811
12812
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012813#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12814 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12815 CONVERT_CHECKED(JSObject, obj, args[0]); \
12816 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12817 }
12818
12819ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12820ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12821ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12822ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12823ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12824ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12825ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12826ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12827ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12828ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12829ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12830ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12831ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12832
12833#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12834
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012835// ----------------------------------------------------------------------------
12836// Implementation of Runtime
12837
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012838#define F(name, number_of_args, result_size) \
12839 { Runtime::k##name, Runtime::RUNTIME, #name, \
12840 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012841
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012842
12843#define I(name, number_of_args, result_size) \
12844 { Runtime::kInline##name, Runtime::INLINE, \
12845 "_" #name, NULL, number_of_args, result_size },
12846
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012847static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012848 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012849 INLINE_FUNCTION_LIST(I)
12850 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012851};
12852
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012854MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12855 Object* dictionary) {
12856 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012857 ASSERT(dictionary != NULL);
12858 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12859 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012860 Object* name_symbol;
12861 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012862 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012863 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12864 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012865 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012866 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12867 String::cast(name_symbol),
12868 Smi::FromInt(i),
12869 PropertyDetails(NONE, NORMAL));
12870 if (!maybe_dictionary->ToObject(&dictionary)) {
12871 // Non-recoverable failure. Calling code must restart heap
12872 // initialization.
12873 return maybe_dictionary;
12874 }
12875 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012876 }
12877 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012878}
12879
12880
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012881const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12882 Heap* heap = name->GetHeap();
12883 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012884 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012885 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012886 int function_index = Smi::cast(smi_index)->value();
12887 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012888 }
12889 return NULL;
12890}
12891
12892
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012893const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012894 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12895}
12896
12897
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012898void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012899 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012900 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012901 if (failure->IsRetryAfterGC()) {
12902 // Try to do a garbage collection; ignore it if it fails. The C
12903 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012904 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012905 } else {
12906 // Handle last resort GC and make sure to allow future allocations
12907 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012908 isolate->counters()->gc_last_resort_from_js()->Increment();
12909 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012910 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012911}
12912
12913
12914} } // namespace v8::internal