blob: cc5aeab78f55c46446b016f848fb60c3ceadc612 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 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"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000043#include "date.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000045#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000046#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000048#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000049#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000050#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000051#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000054#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000057#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000059#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000060#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000061#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
kasperl@chromium.org71affb52009-05-26 05:44:31 +000063namespace v8 {
64namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66
ager@chromium.org3e875802009-06-29 08:26:34 +000067#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000068 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000069
70// Cast the given object to a value of the specified type and store
71// it in a variable with the given name. If the object is not of the
72// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000075 Type* name = Type::cast(args[index]);
76
77#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
78 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 Handle<Type> name = args.at<Type>(index);
80
kasper.lundbd3ec4e2008-07-09 11:06:54 +000081// Cast the given object to a boolean and store it in a variable with
82// the given name. If the object is not a boolean call IllegalOperation
83// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000084#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
85 RUNTIME_ASSERT(args[index]->IsBoolean()); \
86 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000087
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088// Cast the given argument to a Smi and store its value in an int variable
89// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000090// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000091#define CONVERT_SMI_ARG_CHECKED(name, index) \
92 RUNTIME_ASSERT(args[index]->IsSmi()); \
93 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000094
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095// Cast the given argument to a double and store it in a variable with
96// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000098#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
99 RUNTIME_ASSERT(args[index]->IsNumber()); \
100 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101
102// Call the specified converter on the object *comand store the result in
103// a variable of the specified type with the given name. If the
104// object is not a Number call IllegalOperation and return.
105#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
106 RUNTIME_ASSERT(obj->IsNumber()); \
107 type name = NumberTo##Type(obj);
108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000110// Cast the given argument to PropertyDetails and store its value in a
111// variable with the given name. If the argument is not a Smi call
112// IllegalOperation and return.
113#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
114 RUNTIME_ASSERT(args[index]->IsSmi()); \
115 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
116
117
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000118// Assert that the given argument has a valid value for a StrictModeFlag
119// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000120#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
121 RUNTIME_ASSERT(args[index]->IsSmi()); \
122 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
123 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000124 StrictModeFlag name = \
125 static_cast<StrictModeFlag>(args.smi_at(index));
126
127
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000128// Assert that the given argument has a valid value for a LanguageMode
129// and store it in a LanguageMode variable with the given name.
130#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
131 ASSERT(args[index]->IsSmi()); \
132 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
133 args.smi_at(index) == STRICT_MODE || \
134 args.smi_at(index) == EXTENDED_MODE); \
135 LanguageMode name = \
136 static_cast<LanguageMode>(args.smi_at(index));
137
138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
140 JSObject* boilerplate) {
141 StackLimitCheck check(isolate);
142 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 JSObject* copy = JSObject::cast(result);
150
151 // Deep copy local properties.
152 if (copy->HasFastProperties()) {
153 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 for (int i = 0; i < properties->length(); i++) {
155 Object* value = properties->get(i);
156 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000157 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 if (!maybe_result->ToObject(&result)) return maybe_result;
160 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000162 }
163 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000164 int nof = copy->map()->inobject_properties();
165 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 Object* value = copy->InObjectPropertyAt(i);
167 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000168 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000169 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000172 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 }
174 }
175 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000177 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000178 if (!maybe_result->ToObject(&result)) return maybe_result;
179 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000180 FixedArray* names = FixedArray::cast(result);
181 copy->GetLocalPropertyNames(names, 0);
182 for (int i = 0; i < names->length(); i++) {
183 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000184 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000185 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000186 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000187 // Only deep copy fields from the object literal expression.
188 // In particular, don't try to copy the length attribute of
189 // an array.
190 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191 Object* value =
192 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000194 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000195 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
198 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000199 // Creating object copy for literals. No strict mode needed.
200 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000201 if (!maybe_result->ToObject(&result)) return maybe_result;
202 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 }
204 }
205 }
206
207 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000208 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000209 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000210 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000211 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000212 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000214 if (elements->map() == heap->fixed_cow_array_map()) {
215 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000216#ifdef DEBUG
217 for (int i = 0; i < elements->length(); i++) {
218 ASSERT(!elements->get(i)->IsJSObject());
219 }
220#endif
221 } else {
222 for (int i = 0; i < elements->length(); i++) {
223 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000224 ASSERT(value->IsSmi() ||
225 value->IsTheHole() ||
226 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000227 if (value->IsJSObject()) {
228 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
230 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000231 if (!maybe_result->ToObject(&result)) return maybe_result;
232 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000233 elements->set(i, result);
234 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000235 }
236 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000237 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000239 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000240 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000241 int capacity = element_dictionary->Capacity();
242 for (int i = 0; i < capacity; i++) {
243 Object* k = element_dictionary->KeyAt(i);
244 if (element_dictionary->IsKey(k)) {
245 Object* value = element_dictionary->ValueAt(i);
246 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000247 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000248 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
249 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000250 if (!maybe_result->ToObject(&result)) return maybe_result;
251 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000252 element_dictionary->ValueAtPut(i, result);
253 }
254 }
255 }
256 break;
257 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000258 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000259 UNIMPLEMENTED();
260 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000261 case EXTERNAL_PIXEL_ELEMENTS:
262 case EXTERNAL_BYTE_ELEMENTS:
263 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
264 case EXTERNAL_SHORT_ELEMENTS:
265 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
266 case EXTERNAL_INT_ELEMENTS:
267 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
268 case EXTERNAL_FLOAT_ELEMENTS:
269 case EXTERNAL_DOUBLE_ELEMENTS:
270 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000271 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000272 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000273 }
274 return copy;
275}
276
277
ager@chromium.org236ad962008-09-25 09:45:57 +0000278static Handle<Map> ComputeObjectLiteralMap(
279 Handle<Context> context,
280 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000281 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000283 int properties_length = constant_properties->length();
284 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000285 // Check that there are only symbols and array indices among keys.
286 int number_of_symbol_keys = 0;
287 for (int p = 0; p != properties_length; p += 2) {
288 Object* key = constant_properties->get(p);
289 uint32_t element_index = 0;
290 if (key->IsSymbol()) {
291 number_of_symbol_keys++;
292 } else if (key->ToArrayIndex(&element_index)) {
293 // An index key does not require space in the property backing store.
294 number_of_properties--;
295 } else {
296 // Bail out as a non-symbol non-index key makes caching impossible.
297 // ASSERT to make sure that the if condition after the loop is false.
298 ASSERT(number_of_symbol_keys != number_of_properties);
299 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000301 }
302 // If we only have symbols and array indices among keys then we can
303 // use the map cache in the global context.
304 const int kMaxKeys = 10;
305 if ((number_of_symbol_keys == number_of_properties) &&
306 (number_of_symbol_keys < kMaxKeys)) {
307 // Create the fixed array with the key.
308 Handle<FixedArray> keys =
309 isolate->factory()->NewFixedArray(number_of_symbol_keys);
310 if (number_of_symbol_keys > 0) {
311 int index = 0;
312 for (int p = 0; p < properties_length; p += 2) {
313 Object* key = constant_properties->get(p);
314 if (key->IsSymbol()) {
315 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000316 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000318 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000320 *is_result_from_cache = true;
321 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000322 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000323 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000325 Handle<Map>(context->object_function()->initial_map()),
326 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000327}
328
329
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000330static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000332 Handle<FixedArray> literals,
333 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000334
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000335
336static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000337 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000338 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000339 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 bool should_have_fast_elements,
341 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000342 // Get the global context from the literals array. This is the
343 // context in which the function was created and we use the object
344 // function from this context to create the object literal. We do
345 // not use the object function from the current global context
346 // because this might be the object function from another context
347 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000348 Handle<Context> context =
349 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 // In case we have function literals, we want the object to be in
352 // slow properties mode for now. We don't go in the map cache because
353 // maps with constant functions can't be shared if the functions are
354 // not the same (which is the common case).
355 bool is_result_from_cache = false;
356 Handle<Map> map = has_function_literal
357 ? Handle<Map>(context->object_function()->initial_map())
358 : ComputeObjectLiteralMap(context,
359 constant_properties,
360 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000363
364 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000365 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 // Add the constant properties to the boilerplate.
368 int length = constant_properties->length();
369 bool should_transform =
370 !is_result_from_cache && boilerplate->HasFastProperties();
371 if (should_transform || has_function_literal) {
372 // Normalize the properties of object to avoid n^2 behavior
373 // when extending the object multiple properties. Indicate the number of
374 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000375 JSObject::NormalizeProperties(
376 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 }
378
379 for (int index = 0; index < length; index +=2) {
380 Handle<Object> key(constant_properties->get(index+0), isolate);
381 Handle<Object> value(constant_properties->get(index+1), isolate);
382 if (value->IsFixedArray()) {
383 // The value contains the constant_properties of a
384 // simple object or array literal.
385 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
386 value = CreateLiteralBoilerplate(isolate, literals, array);
387 if (value.is_null()) return value;
388 }
389 Handle<Object> result;
390 uint32_t element_index = 0;
391 if (key->IsSymbol()) {
392 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
393 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000394 result = JSObject::SetOwnElement(
395 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 Handle<String> name(String::cast(*key));
398 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000399 result = JSObject::SetLocalPropertyIgnoreAttributes(
400 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000402 } else if (key->ToArrayIndex(&element_index)) {
403 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000404 result = JSObject::SetOwnElement(
405 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406 } else {
407 // Non-uint32 number.
408 ASSERT(key->IsNumber());
409 double num = key->Number();
410 char arr[100];
411 Vector<char> buffer(arr, ARRAY_SIZE(arr));
412 const char* str = DoubleToCString(num, buffer);
413 Handle<String> name =
414 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000415 result = JSObject::SetLocalPropertyIgnoreAttributes(
416 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 // If setting the property on the boilerplate throws an
419 // exception, the exception is converted to an empty handle in
420 // the handle based operations. In that case, we need to
421 // convert back to an exception.
422 if (result.is_null()) return result;
423 }
424
425 // Transform to fast properties if necessary. For object literals with
426 // containing function literals we defer this operation until after all
427 // computed properties have been assigned so that we can generate
428 // constant function properties.
429 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000430 JSObject::TransformToFastProperties(
431 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
433
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000434 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000435}
436
437
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000438MaybeObject* TransitionElements(Handle<Object> object,
439 ElementsKind to_kind,
440 Isolate* isolate) {
441 HandleScope scope(isolate);
442 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
443 ElementsKind from_kind =
444 Handle<JSObject>::cast(object)->map()->elements_kind();
445 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
446 Handle<Object> result = JSObject::TransitionElementsKind(
447 Handle<JSObject>::cast(object), to_kind);
448 if (result.is_null()) return isolate->ThrowIllegalOperation();
449 return *result;
450 }
451 return isolate->ThrowIllegalOperation();
452}
453
454
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000455static const int kSmiOnlyLiteralMinimumLength = 1024;
456
457
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000458Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000459 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000460 Handle<FixedArray> literals,
461 Handle<FixedArray> elements) {
462 // Create the JSArray.
463 Handle<JSFunction> constructor(
464 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000465 Handle<JSArray> object =
466 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000468 ElementsKind constant_elements_kind =
469 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
470 Handle<FixedArrayBase> constant_elements_values(
471 FixedArrayBase::cast(elements->get(1)));
472
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000473 Context* global_context = isolate->context()->global_context();
474 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
475 object->set_map(Map::cast(global_context->smi_js_array_map()));
476 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
477 object->set_map(Map::cast(global_context->double_js_array_map()));
478 } else {
479 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000482 Handle<FixedArrayBase> copied_elements_values;
483 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
484 ASSERT(FLAG_smi_only_arrays);
485 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
486 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000487 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000488 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
489 constant_elements_kind == FAST_ELEMENTS);
490 const bool is_cow =
491 (constant_elements_values->map() ==
492 isolate->heap()->fixed_cow_array_map());
493 if (is_cow) {
494 copied_elements_values = constant_elements_values;
495#if DEBUG
496 Handle<FixedArray> fixed_array_values =
497 Handle<FixedArray>::cast(copied_elements_values);
498 for (int i = 0; i < fixed_array_values->length(); i++) {
499 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
500 }
501#endif
502 } else {
503 Handle<FixedArray> fixed_array_values =
504 Handle<FixedArray>::cast(constant_elements_values);
505 Handle<FixedArray> fixed_array_values_copy =
506 isolate->factory()->CopyFixedArray(fixed_array_values);
507 copied_elements_values = fixed_array_values_copy;
508 for (int i = 0; i < fixed_array_values->length(); i++) {
509 Object* current = fixed_array_values->get(i);
510 if (current->IsFixedArray()) {
511 // The value contains the constant_properties of a
512 // simple object or array literal.
513 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
514 Handle<Object> result =
515 CreateLiteralBoilerplate(isolate, literals, fa);
516 if (result.is_null()) return result;
517 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000518 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000519 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000520 }
521 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000522 object->set_elements(*copied_elements_values);
523 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000524
525 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
526 // on or the object is larger than the threshold.
527 if (!FLAG_smi_only_arrays &&
528 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
529 if (object->GetElementsKind() != FAST_ELEMENTS) {
530 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
531 }
532 }
533
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000534 return object;
535}
536
537
538static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000540 Handle<FixedArray> literals,
541 Handle<FixedArray> array) {
542 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000543 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000544 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000545 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return CreateObjectLiteralBoilerplate(isolate,
547 literals,
548 elements,
549 true,
550 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000551 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 return CreateObjectLiteralBoilerplate(isolate,
553 literals,
554 elements,
555 false,
556 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000557 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000558 return Runtime::CreateArrayLiteralBoilerplate(
559 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000560 default:
561 UNREACHABLE();
562 return Handle<Object>::null();
563 }
564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000569 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000570 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000571 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000572 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000573 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
575 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576
577 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 Handle<Object> boilerplate(literals->get(literals_index), isolate);
579 if (*boilerplate == isolate->heap()->undefined_value()) {
580 boilerplate = CreateObjectLiteralBoilerplate(isolate,
581 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000582 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 should_have_fast_elements,
584 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000585 if (boilerplate.is_null()) return Failure::Exception();
586 // Update the functions literal and return the boilerplate.
587 literals->set(literals_index, *boilerplate);
588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590}
591
592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000593RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000594 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000595 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000596 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000597 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000598 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000599 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
601 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602
603 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000604 Handle<Object> boilerplate(literals->get(literals_index), isolate);
605 if (*boilerplate == isolate->heap()->undefined_value()) {
606 boilerplate = CreateObjectLiteralBoilerplate(isolate,
607 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000608 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 should_have_fast_elements,
610 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000611 if (boilerplate.is_null()) return Failure::Exception();
612 // Update the functions literal and return the boilerplate.
613 literals->set(literals_index, *boilerplate);
614 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000616}
617
618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000619RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000621 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000622 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000623 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000624 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000625
626 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 Handle<Object> boilerplate(literals->get(literals_index), isolate);
628 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000629 boilerplate =
630 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000631 if (boilerplate.is_null()) return Failure::Exception();
632 // Update the functions literal and return the boilerplate.
633 literals->set(literals_index, *boilerplate);
634 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000636}
637
638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000641 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000642 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000643 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000644 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000645
646 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 Handle<Object> boilerplate(literals->get(literals_index), isolate);
648 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000649 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000650 boilerplate =
651 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000652 if (boilerplate.is_null()) return Failure::Exception();
653 // Update the functions literal and return the boilerplate.
654 literals->set(literals_index, *boilerplate);
655 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000656 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000658 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661}
662
663
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
665 ASSERT(args.length() == 2);
666 Object* handler = args[0];
667 Object* prototype = args[1];
668 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000670 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
671}
672
673
lrn@chromium.org34e60782011-09-15 07:25:40 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
675 ASSERT(args.length() == 4);
676 Object* handler = args[0];
677 Object* call_trap = args[1];
678 Object* construct_trap = args[2];
679 Object* prototype = args[3];
680 Object* used_prototype =
681 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
682 return isolate->heap()->AllocateJSFunctionProxy(
683 handler, call_trap, construct_trap, used_prototype);
684}
685
686
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000687RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000690 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691}
692
693
lrn@chromium.org34e60782011-09-15 07:25:40 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
695 ASSERT(args.length() == 1);
696 Object* obj = args[0];
697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
698}
699
700
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
702 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000703 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000704 return proxy->handler();
705}
706
707
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000710 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000717 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000718 return proxy->construct_trap();
719}
720
721
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
723 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000724 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000725 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000726 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000727}
728
729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000733 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000734 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
735 holder->set_table(*table);
736 return *holder;
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000743 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetAdd(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000755 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 return isolate->heap()->ToBoolean(table->Contains(*key));
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000765 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000766 Handle<Object> key(args[1]);
767 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
768 table = ObjectHashSetRemove(table, key);
769 holder->set_table(*table);
770 return isolate->heap()->undefined_symbol();
771}
772
773
774RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000777 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000778 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
779 holder->set_table(*table);
780 return *holder;
781}
782
783
784RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000787 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000788 Handle<Object> key(args[1]);
789 return ObjectHashTable::cast(holder->table())->Lookup(*key);
790}
791
792
793RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
794 HandleScope scope(isolate);
795 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000796 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000797 Handle<Object> key(args[1]);
798 Handle<Object> value(args[2]);
799 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
800 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
801 holder->set_table(*new_table);
802 return *value;
803}
804
805
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
807 HandleScope scope(isolate);
808 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000809 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810 ASSERT(weakmap->map()->inobject_properties() == 0);
811 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
812 weakmap->set_table(*table);
813 weakmap->set_next(Smi::FromInt(0));
814 return *weakmap;
815}
816
817
818RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
819 NoHandleAllocation ha;
820 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000821 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
822 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000823 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000824}
825
826
827RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
828 HandleScope scope(isolate);
829 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000830 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
831 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000832 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000833 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000834 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
835 weakmap->set_table(*new_table);
836 return *value;
837}
838
839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000840RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
843 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 return JSObject::cast(obj)->class_name();
846}
847
ager@chromium.org7c537e22008-10-16 08:43:32 +0000848
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000852 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000853 Object* obj = input_obj;
854 // We don't expect access checks to be needed on JSProxy objects.
855 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000856 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000857 if (obj->IsAccessCheckNeeded() &&
858 !isolate->MayNamedAccess(JSObject::cast(obj),
859 isolate->heap()->Proto_symbol(),
860 v8::ACCESS_GET)) {
861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
862 return isolate->heap()->undefined_value();
863 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000864 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000865 } while (obj->IsJSObject() &&
866 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000867 return obj;
868}
869
870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000871RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
875 Object* O = args[0];
876 Object* V = args[1];
877 while (true) {
878 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 if (prototype->IsNull()) return isolate->heap()->false_value();
880 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 V = prototype;
882 }
883}
884
885
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000886// Recursively traverses hidden prototypes if property is not found
887static void GetOwnPropertyImplementation(JSObject* obj,
888 String* name,
889 LookupResult* result) {
890 obj->LocalLookupRealNamedProperty(name, result);
891
892 if (!result->IsProperty()) {
893 Object* proto = obj->GetPrototype();
894 if (proto->IsJSObject() &&
895 JSObject::cast(proto)->map()->is_hidden_prototype())
896 GetOwnPropertyImplementation(JSObject::cast(proto),
897 name, result);
898 }
899}
900
901
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000902static bool CheckAccessException(LookupResult* result,
903 v8::AccessType access_type) {
904 if (result->type() == CALLBACKS) {
905 Object* callback = result->GetCallbackObject();
906 if (callback->IsAccessorInfo()) {
907 AccessorInfo* info = AccessorInfo::cast(callback);
908 bool can_access =
909 (access_type == v8::ACCESS_HAS &&
910 (info->all_can_read() || info->all_can_write())) ||
911 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
912 (access_type == v8::ACCESS_SET && info->all_can_write());
913 return can_access;
914 }
915 }
916
917 return false;
918}
919
920
921static bool CheckAccess(JSObject* obj,
922 String* name,
923 LookupResult* result,
924 v8::AccessType access_type) {
925 ASSERT(result->IsProperty());
926
927 JSObject* holder = result->holder();
928 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000930 while (true) {
931 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000933 // Access check callback denied the access, but some properties
934 // can have a special permissions which override callbacks descision
935 // (currently see v8::AccessControl).
936 break;
937 }
938
939 if (current == holder) {
940 return true;
941 }
942
943 current = JSObject::cast(current->GetPrototype());
944 }
945
946 // API callbacks can have per callback access exceptions.
947 switch (result->type()) {
948 case CALLBACKS: {
949 if (CheckAccessException(result, access_type)) {
950 return true;
951 }
952 break;
953 }
954 case INTERCEPTOR: {
955 // If the object has an interceptor, try real named properties.
956 // Overwrite the result to fetch the correct property later.
957 holder->LookupRealNamedProperty(name, result);
958 if (result->IsProperty()) {
959 if (CheckAccessException(result, access_type)) {
960 return true;
961 }
962 }
963 break;
964 }
965 default:
966 break;
967 }
968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000970 return false;
971}
972
973
974// TODO(1095): we should traverse hidden prototype hierachy as well.
975static bool CheckElementAccess(JSObject* obj,
976 uint32_t index,
977 v8::AccessType access_type) {
978 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000979 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000980 return false;
981 }
982
983 return true;
984}
985
986
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000987// Enumerator used as indices into the array returned from GetOwnProperty
988enum PropertyDescriptorIndices {
989 IS_ACCESSOR_INDEX,
990 VALUE_INDEX,
991 GETTER_INDEX,
992 SETTER_INDEX,
993 WRITABLE_INDEX,
994 ENUMERABLE_INDEX,
995 CONFIGURABLE_INDEX,
996 DESCRIPTOR_SIZE
997};
998
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000999
1000static MaybeObject* GetOwnProperty(Isolate* isolate,
1001 Handle<JSObject> obj,
1002 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 Heap* heap = isolate->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1005 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001006 LookupResult result(isolate);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001007 // This could be an element.
1008 uint32_t index;
1009 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001010 switch (obj->HasLocalElement(index)) {
1011 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001012 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001013
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001014 case JSObject::STRING_CHARACTER_ELEMENT: {
1015 // Special handling of string objects according to ECMAScript 5
1016 // 15.5.5.2. Note that this might be a string object with elements
1017 // other than the actual string value. This is covered by the
1018 // subsequent cases.
1019 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1020 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001021 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001023 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001024 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001025 elms->set(WRITABLE_INDEX, heap->false_value());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001026 elms->set(ENUMERABLE_INDEX, heap->true_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001027 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001028 return *desc;
1029 }
1030
1031 case JSObject::INTERCEPTED_ELEMENT:
1032 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001034 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001036 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001037 elms->set(WRITABLE_INDEX, heap->true_value());
1038 elms->set(ENUMERABLE_INDEX, heap->true_value());
1039 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001040 return *desc;
1041 }
1042
1043 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001044 Handle<JSObject> holder = obj;
1045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001047 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001048 ASSERT(proto->IsJSGlobalObject());
1049 holder = Handle<JSObject>(JSObject::cast(proto));
1050 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001051 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001052 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001053 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001055 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001056 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001057 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001058 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001059 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001060 PropertyDetails details = dictionary->DetailsAt(entry);
1061 switch (details.type()) {
1062 case CALLBACKS: {
1063 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001064 AccessorPair* accessors =
1065 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001066 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001067 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001068 elms->set(GETTER_INDEX, accessors->SafeGet(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001069 }
1070 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001071 elms->set(SETTER_INDEX, accessors->SafeGet(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001072 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001073 break;
1074 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001076 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001077 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001078 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001079 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001080 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001081 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001082 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001083 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 default:
1085 UNREACHABLE();
1086 break;
1087 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1089 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 return *desc;
1091 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001092 }
1093 }
1094
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001095 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001096 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001097
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001098 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001099 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001100 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001101
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001102 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001103 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001104 }
1105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001106 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1107 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001108
1109 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001110 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001111
1112 if (is_js_accessor) {
1113 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001114 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001115
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001116 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001117 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001118 elms->set(GETTER_INDEX, accessors->SafeGet(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001119 }
1120 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001121 elms->set(SETTER_INDEX, accessors->SafeGet(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001122 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001123 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001124 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1125 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001126
1127 PropertyAttributes attrs;
1128 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001129 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001130 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1131 if (!maybe_value->ToObject(&value)) return maybe_value;
1132 }
1133 elms->set(VALUE_INDEX, value);
1134 }
1135
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001136 return *desc;
1137}
1138
1139
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001140// Returns an array with the property description:
1141// if args[1] is not a property on args[0]
1142// returns undefined
1143// if args[1] is a data property on args[0]
1144// [false, value, Writeable, Enumerable, Configurable]
1145// if args[1] is an accessor on args[0]
1146// [true, GetFunction, SetFunction, Enumerable, Configurable]
1147RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1148 ASSERT(args.length() == 2);
1149 HandleScope scope(isolate);
1150 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1151 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
1152 return GetOwnProperty(isolate, obj, name);
1153}
1154
1155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001156RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001157 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001158 CONVERT_ARG_CHECKED(JSObject, obj, 0);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001159 return obj->PreventExtensions();
1160}
1161
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001163RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001164 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001165 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001166 if (obj->IsJSGlobalProxy()) {
1167 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001169 ASSERT(proto->IsJSGlobalObject());
1170 obj = JSObject::cast(proto);
1171 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001172 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001173}
1174
1175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001176RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001179 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1180 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1181 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001182 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1183 if (result.is_null()) return Failure::Exception();
1184 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185}
1186
1187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001188RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001191 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001196RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 ASSERT(args.length() == 1);
1198 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001199 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201}
1202
1203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001204RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001206 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1207 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001208 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1209 InstanceType type = templ->map()->instance_type();
1210 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1211 type == OBJECT_TEMPLATE_INFO_TYPE);
1212 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001213 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001214 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1215 } else {
1216 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1217 }
1218 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219}
1220
1221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001222RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001223 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001224 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001225 Map* old_map = object->map();
1226 bool needs_access_checks = old_map->is_access_check_needed();
1227 if (needs_access_checks) {
1228 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001229 Object* new_map;
1230 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1231 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1232 }
ager@chromium.org32912102009-01-16 10:38:43 +00001233
1234 Map::cast(new_map)->set_is_access_check_needed(false);
1235 object->set_map(Map::cast(new_map));
1236 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001237 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001238}
1239
1240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001241RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001242 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001243 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001244 Map* old_map = object->map();
1245 if (!old_map->is_access_check_needed()) {
1246 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001247 Object* new_map;
1248 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1249 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1250 }
ager@chromium.org32912102009-01-16 10:38:43 +00001251
1252 Map::cast(new_map)->set_is_access_check_needed(true);
1253 object->set_map(Map::cast(new_map));
1254 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001255 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001256}
1257
1258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259static Failure* ThrowRedeclarationError(Isolate* isolate,
1260 const char* type,
1261 Handle<String> name) {
1262 HandleScope scope(isolate);
1263 Handle<Object> type_handle =
1264 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 Handle<Object> args[2] = { type_handle, name };
1266 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1268 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269}
1270
1271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001272RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001274 HandleScope scope(isolate);
1275 Handle<GlobalObject> global = Handle<GlobalObject>(
1276 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
ager@chromium.org3811b432009-10-28 14:53:37 +00001278 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001279 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001280 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 // Traverse the name/value pairs and set the properties.
1283 int length = pairs->length();
1284 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001285 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288
1289 // We have to declare a global const property. To capture we only
1290 // assign to it when evaluating the assignment for "const x =
1291 // <expr>" the initial value is the hole.
1292 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001293 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 if (value->IsUndefined() || is_const_property) {
1295 // Lookup the property in the global object, and don't set the
1296 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001297 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 global->Lookup(*name, &lookup);
1299 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 // We found an existing property. Unless it was an interceptor
1301 // that claims the property is absent, skip this declaration.
1302 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 continue;
1304 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001305 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1306 if (attributes != ABSENT) {
1307 continue;
1308 }
1309 // Fall-through and introduce the absent property by using
1310 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 }
1312 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001313 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001315 Handle<SharedFunctionInfo> shared =
1316 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1319 context,
1320 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321 value = function;
1322 }
1323
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001324 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 global->LocalLookup(*name, &lookup);
1326
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001327 // Compute the property attributes. According to ECMA-262, section
1328 // 13, page 71, the property must be read-only and
1329 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1330 // property as read-only, so we don't either.
1331 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001332 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001333 attr |= DONT_DELETE;
1334 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001335 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001336 if (is_const_property || (is_native && is_function_declaration)) {
1337 attr |= READ_ONLY;
1338 }
1339
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 // Safari does not allow the invocation of callback setters for
1341 // function declarations. To mimic this behavior, we do not allow
1342 // the invocation of setters for function values. This makes a
1343 // difference for global functions with the same names as event
1344 // handlers such as "function onload() {}". Firefox does call the
1345 // onload setter in those case and Safari does not. We follow
1346 // Safari for compatibility.
1347 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001348 // Do not change DONT_DELETE to false from true.
1349 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001350 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001351 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001352 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1353
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001354 RETURN_IF_EMPTY_HANDLE(
1355 isolate,
1356 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1357 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001359 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1360 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1361 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001362 RETURN_IF_EMPTY_HANDLE(
1363 isolate,
1364 JSReceiver::SetProperty(global, name, value,
1365 static_cast<PropertyAttributes>(attr),
1366 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367 }
1368 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001370 ASSERT(!isolate->has_pending_exception());
1371 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372}
1373
1374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001375RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001376 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001378
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001379 // Declarations are always made in a function or global context. In the
1380 // case of eval code, the context passed is the context of the caller,
1381 // which may be some nested context and not the declaration context.
1382 RUNTIME_ASSERT(args[0]->IsContext());
1383 Handle<Context> context(Context::cast(args[0])->declaration_context());
1384
ager@chromium.org7c537e22008-10-16 08:43:32 +00001385 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001386 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001387 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001388 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390 int index;
1391 PropertyAttributes attributes;
1392 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001393 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001394 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001395 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396
1397 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001398 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1400 // Functions are not read-only.
1401 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1402 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001403 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404 }
1405
1406 // Initialize it if necessary.
1407 if (*initial_value != NULL) {
1408 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001409 ASSERT(holder.is_identical_to(context));
1410 if (((attributes & READ_ONLY) == 0) ||
1411 context->get(index)->IsTheHole()) {
1412 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 }
1414 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001415 // Slow case: The property is in the context extension object of a
1416 // function context or the global object of a global context.
1417 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001418 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001419 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001420 JSReceiver::SetProperty(object, name, initial_value, mode,
1421 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 }
1423 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001426 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001427 // "declared" in the function context's extension context or as a
1428 // property of the the global object.
1429 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001430 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001431 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001432 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001433 // Context extension objects are allocated lazily.
1434 ASSERT(context->IsFunctionContext());
1435 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001436 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001437 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001438 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001439 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440
ager@chromium.org7c537e22008-10-16 08:43:32 +00001441 // Declare the property by setting it to the initial value if provided,
1442 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1443 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001444 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001445 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001446 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001447 // Declaring a const context slot is a conflicting declaration if
1448 // there is a callback with that name in a prototype. It is
1449 // allowed to introduce const variables in
1450 // JSContextExtensionObjects. They are treated specially in
1451 // SetProperty and no setters are invoked for those since they are
1452 // not real JSObjects.
1453 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001454 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001455 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001456 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001457 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001459 }
1460 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001461 RETURN_IF_EMPTY_HANDLE(
1462 isolate,
1463 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001464 }
1465
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001466 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467}
1468
1469
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001470RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001472 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001473 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001474 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475
1476 // Determine if we need to assign to the variable if it already
1477 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001478 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1479 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001481 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001482 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001484 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1485 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1486 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487
1488 // According to ECMA-262, section 12.2, page 62, the property must
1489 // not be deletable.
1490 PropertyAttributes attributes = DONT_DELETE;
1491
1492 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001493 // there, there is a property with this name in the prototype chain.
1494 // We follow Safari and Firefox behavior and only set the property
1495 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001496 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001497 // Note that objects can have hidden prototypes, so we need to traverse
1498 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001499 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001500 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 while (object->IsJSObject() &&
1502 JSObject::cast(object)->map()->is_hidden_prototype()) {
1503 JSObject* raw_holder = JSObject::cast(object);
1504 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001505 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 HandleScope handle_scope(isolate);
1507 Handle<JSObject> holder(raw_holder);
1508 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1509 // Update the raw pointer in case it's changed due to GC.
1510 raw_holder = *holder;
1511 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1512 // Found an interceptor that's not read only.
1513 if (assign) {
1514 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001515 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001516 } else {
1517 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001518 }
1519 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001520 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001521 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001522 }
1523
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001524 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001525 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001526 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001527 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001528 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001529 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001530}
1531
1532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001533RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 // All constants are declared with an initial value. The name
1535 // of the constant is the first argument and the initial value
1536 // is the second.
1537 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001538 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539 Handle<Object> value = args.at<Object>(1);
1540
1541 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543
1544 // According to ECMA-262, section 12.2, page 62, the property must
1545 // not be deletable. Since it's a const, it must be READ_ONLY too.
1546 PropertyAttributes attributes =
1547 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1548
1549 // Lookup the property locally in the global object. If it isn't
1550 // there, we add the property and take special precautions to always
1551 // add it as a local property even in case of callbacks in the
1552 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001553 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001554 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 global->LocalLookup(*name, &lookup);
1556 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001557 return global->SetLocalPropertyIgnoreAttributes(*name,
1558 *value,
1559 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 }
1561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001564 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001565 HandleScope handle_scope(isolate);
1566 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001567
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001568 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 // property through an interceptor and only do it if it's
1570 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001571 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001572 RETURN_IF_EMPTY_HANDLE(
1573 isolate,
1574 JSReceiver::SetProperty(global, name, value, attributes,
1575 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 return *value;
1577 }
1578
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001579 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 // constant. For now, we determine this by checking if the
1581 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001582 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583 PropertyType type = lookup.type();
1584 if (type == FIELD) {
1585 FixedArray* properties = global->properties();
1586 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001587 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 properties->set(index, *value);
1589 }
1590 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001591 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1592 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001593 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594 }
1595 } else {
1596 // Ignore re-initialization of constants that have already been
1597 // assigned a function value.
1598 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1599 }
1600
1601 // Use the set value as the result of the operation.
1602 return *value;
1603}
1604
1605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001606RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001607 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608 ASSERT(args.length() == 3);
1609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001610 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001613 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001614 RUNTIME_ASSERT(args[1]->IsContext());
1615 Handle<Context> context(Context::cast(args[1])->declaration_context());
1616
1617 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618
1619 int index;
1620 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001621 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001622 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001623 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001624 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001627 ASSERT(holder->IsContext());
1628 // Property was found in a context. Perform the assignment if we
1629 // found some non-constant or an uninitialized constant.
1630 Handle<Context> context = Handle<Context>::cast(holder);
1631 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1632 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001633 }
1634 return *value;
1635 }
1636
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001637 // The property could not be found, we introduce it as a property of the
1638 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001639 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001640 Handle<JSObject> global = Handle<JSObject>(
1641 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001642 // Strict mode not needed (const disallowed in strict mode).
1643 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001644 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001645 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001646 return *value;
1647 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001648
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001649 // The property was present in some function's context extension object,
1650 // as a property on the subject of a with, or as a property of the global
1651 // object.
1652 //
1653 // In most situations, eval-introduced consts should still be present in
1654 // the context extension object. However, because declaration and
1655 // initialization are separate, the property might have been deleted
1656 // before we reach the initialization point.
1657 //
1658 // Example:
1659 //
1660 // function f() { eval("delete x; const x;"); }
1661 //
1662 // In that case, the initialization behaves like a normal assignment.
1663 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001664
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001665 if (*object == context->extension()) {
1666 // This is the property that was introduced by the const declaration.
1667 // Set it if it hasn't been set before. NOTE: We cannot use
1668 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001669 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001670 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001671 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001672 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1673
1674 PropertyType type = lookup.type();
1675 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001676 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001677 int index = lookup.GetFieldIndex();
1678 if (properties->get(index)->IsTheHole()) {
1679 properties->set(index, *value);
1680 }
1681 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001682 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1683 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001684 }
1685 } else {
1686 // We should not reach here. Any real, named property should be
1687 // either a field or a dictionary slot.
1688 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689 }
1690 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001691 // The property was found on some other object. Set it if it is not a
1692 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001693 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001694 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001695 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001696 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001697 JSReceiver::SetProperty(object, name, value, attributes,
1698 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702 return *value;
1703}
1704
1705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001706RUNTIME_FUNCTION(MaybeObject*,
1707 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001708 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001709 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001710 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001711 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001712 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001713 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001714 }
1715 return *object;
1716}
1717
1718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001719RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001720 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001721 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001722 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1723 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001724 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001725 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001726 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001727 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001728 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001729 RUNTIME_ASSERT(index >= 0);
1730 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001732 Handle<Object> result = RegExpImpl::Exec(regexp,
1733 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001734 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001735 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001736 if (result.is_null()) return Failure::Exception();
1737 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001738}
1739
1740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001741RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001742 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001743 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001744 if (elements_count < 0 ||
1745 elements_count > FixedArray::kMaxLength ||
1746 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001748 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749 Object* new_object;
1750 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001752 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1753 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1756 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1758 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001759 {
1760 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001761 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001762 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001764 }
1765 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001767 array->set_elements(elements);
1768 array->set_length(Smi::FromInt(elements_count));
1769 // Write in-object properties after the length of the array.
1770 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1771 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1772 return array;
1773}
1774
1775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001776RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777 AssertNoAllocation no_alloc;
1778 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001779 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1780 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001781
1782 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001783 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001784
1785 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001786 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001787
1788 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001790
1791 Map* map = regexp->map();
1792 Object* constructor = map->constructor();
1793 if (constructor->IsJSFunction() &&
1794 JSFunction::cast(constructor)->initial_map() == map) {
1795 // If we still have the original map, set in-object properties directly.
1796 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001797 // Both true and false are immovable immortal objects so no need for write
1798 // barrier.
1799 regexp->InObjectPropertyAtPut(
1800 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1801 regexp->InObjectPropertyAtPut(
1802 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1803 regexp->InObjectPropertyAtPut(
1804 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001805 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1806 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001807 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001808 return regexp;
1809 }
1810
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001812 PropertyAttributes final =
1813 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1814 PropertyAttributes writable =
1815 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001817 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001818 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001819 source,
1820 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001822 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001823 global,
1824 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001825 ASSERT(!result->IsFailure());
1826 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001828 ignoreCase,
1829 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001830 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001832 multiline,
1833 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001834 ASSERT(!result->IsFailure());
1835 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001837 Smi::FromInt(0),
1838 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839 ASSERT(!result->IsFailure());
1840 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001841 return regexp;
1842}
1843
1844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001845RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001846 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001847 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001848 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001849 // This is necessary to enable fast checks for absence of elements
1850 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001851 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001852 return Smi::FromInt(0);
1853}
1854
1855
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1857 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001858 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001859 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1861 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1862 Handle<JSFunction> optimized =
1863 isolate->factory()->NewFunction(key,
1864 JS_OBJECT_TYPE,
1865 JSObject::kHeaderSize,
1866 code,
1867 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001868 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001869 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001870 return optimized;
1871}
1872
1873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001874RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001875 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001876 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001877 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001878
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001879 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1880 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1881 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1882 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1883 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1884 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1885 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001886
1887 return *holder;
1888}
1889
1890
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001891RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001892 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001893 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001894
1895 if (!callable->IsJSFunction()) {
1896 HandleScope scope(isolate);
1897 bool threw = false;
1898 Handle<Object> delegate =
1899 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1900 if (threw) return Failure::Exception();
1901 callable = JSFunction::cast(*delegate);
1902 }
1903 JSFunction* function = JSFunction::cast(callable);
1904
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001905 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001906 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001907 return isolate->heap()->undefined_value();
1908 }
1909 // Returns undefined for strict or native functions, or
1910 // the associated global receiver for "normal" functions.
1911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001912 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001913 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001914 return global_context->global()->global_receiver();
1915}
1916
1917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001918RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001919 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001920 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001921 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001922 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001923 Handle<String> pattern = args.at<String>(2);
1924 Handle<String> flags = args.at<String>(3);
1925
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001926 // Get the RegExp function from the context in the literals array.
1927 // This is the RegExp function from the context in which the
1928 // function was created. We do not use the RegExp function from the
1929 // current global context because this might be the RegExp function
1930 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001931 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001932 Handle<JSFunction>(
1933 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934 // Compute the regular expression literal.
1935 bool has_pending_exception;
1936 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001937 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1938 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001940 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 return Failure::Exception();
1942 }
1943 literals->set(index, *regexp);
1944 return *regexp;
1945}
1946
1947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001952 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 return f->shared()->name();
1954}
1955
1956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 2);
1960
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001961 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1962 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001963 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001964 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001965}
1966
1967
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001968RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1969 NoHandleAllocation ha;
1970 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001971 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001972 return isolate->heap()->ToBoolean(
1973 f->shared()->name_should_print_as_anonymous());
1974}
1975
1976
1977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1978 NoHandleAllocation ha;
1979 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001980 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001981 f->shared()->set_name_should_print_as_anonymous(true);
1982 return isolate->heap()->undefined_value();
1983}
1984
1985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001986RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001987 NoHandleAllocation ha;
1988 ASSERT(args.length() == 1);
1989
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001990 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001991 Object* obj = f->RemovePrototype();
1992 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001993
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001994 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001995}
1996
1997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001999 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002000 ASSERT(args.length() == 1);
2001
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002002 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002003 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2004 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002005
2006 return *GetScriptWrapper(Handle<Script>::cast(script));
2007}
2008
2009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002010RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002011 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002012 ASSERT(args.length() == 1);
2013
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002014 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002015 Handle<SharedFunctionInfo> shared(f->shared());
2016 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002017}
2018
2019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002020RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021 NoHandleAllocation ha;
2022 ASSERT(args.length() == 1);
2023
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002024 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002025 int pos = fun->shared()->start_position();
2026 return Smi::FromInt(pos);
2027}
2028
2029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002030RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002031 ASSERT(args.length() == 2);
2032
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002033 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002034 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2035
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002036 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2037
2038 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002039 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002040}
2041
2042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002043RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 2);
2046
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002047 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2048 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051}
2052
2053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002054RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002055 NoHandleAllocation ha;
2056 ASSERT(args.length() == 2);
2057
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002058 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2059 CONVERT_SMI_ARG_CHECKED(length, 1);
2060 fun->shared()->set_length(length);
2061 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002062}
2063
2064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002065RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002066 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002067 ASSERT(args.length() == 2);
2068
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002069 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002070 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002071 Object* obj;
2072 { MaybeObject* maybe_obj =
2073 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2074 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2075 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002076 return args[0]; // return TOS
2077}
2078
2079
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002080RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2081 NoHandleAllocation ha;
2082 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002083 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002084
2085 MaybeObject* maybe_name =
2086 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2087 String* name;
2088 if (!maybe_name->To(&name)) return maybe_name;
2089
2090 if (function->HasFastProperties()) {
2091 // Construct a new field descriptor with updated attributes.
2092 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2093 int index = instance_desc->Search(name);
2094 ASSERT(index != DescriptorArray::kNotFound);
2095 PropertyDetails details(instance_desc->GetDetails(index));
2096 CallbacksDescriptor new_desc(name,
2097 instance_desc->GetValue(index),
2098 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2099 details.index());
2100 // Construct a new field descriptors array containing the new descriptor.
2101 Object* descriptors_unchecked;
2102 { MaybeObject* maybe_descriptors_unchecked =
2103 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2104 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2105 return maybe_descriptors_unchecked;
2106 }
2107 }
2108 DescriptorArray* new_descriptors =
2109 DescriptorArray::cast(descriptors_unchecked);
2110 // Create a new map featuring the new field descriptors array.
2111 Object* map_unchecked;
2112 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2113 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2114 return maybe_map_unchecked;
2115 }
2116 }
2117 Map* new_map = Map::cast(map_unchecked);
2118 new_map->set_instance_descriptors(new_descriptors);
2119 function->set_map(new_map);
2120 } else { // Dictionary properties.
2121 // Directly manipulate the property details.
2122 int entry = function->property_dictionary()->FindEntry(name);
2123 ASSERT(entry != StringDictionary::kNotFound);
2124 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2125 PropertyDetails new_details(
2126 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2127 details.type(),
2128 details.index());
2129 function->property_dictionary()->DetailsAtPut(entry, new_details);
2130 }
2131 return function;
2132}
2133
2134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002135RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002136 NoHandleAllocation ha;
2137 ASSERT(args.length() == 1);
2138
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002139 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002140 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002141}
2142
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002144RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002145 NoHandleAllocation ha;
2146 ASSERT(args.length() == 1);
2147
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002148 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002149 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002150}
2151
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002153RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002154 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002155 ASSERT(args.length() == 2);
2156
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002157 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002158 Handle<Object> code = args.at<Object>(1);
2159
2160 Handle<Context> context(target->context());
2161
2162 if (!code->IsNull()) {
2163 RUNTIME_ASSERT(code->IsJSFunction());
2164 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002165 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002166
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002167 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002168 return Failure::Exception();
2169 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002170 // Since we don't store the source for this we should never
2171 // optimize this.
2172 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002173 // Set the code, scope info, formal parameter count,
2174 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002175 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002176 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002177 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002178 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002179 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002180 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002181 // Set the source code of the target function to undefined.
2182 // SetCode is only used for built-in constructors like String,
2183 // Array, and Object, and some web code
2184 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002185 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002186 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002187 // Clear the optimization hints related to the compiled code as these are no
2188 // longer valid when the code is overwritten.
2189 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190 context = Handle<Context>(fun->context());
2191
2192 // Make sure we get a fresh copy of the literal vector to avoid
2193 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002194 int number_of_literals = fun->NumberOfLiterals();
2195 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002196 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002198 // Insert the object, regexp and array functions in the literals
2199 // array prefix. These are the functions that will be used when
2200 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002201 literals->set(JSFunction::kLiteralGlobalContextIndex,
2202 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002203 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002204 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002205 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002206
2207 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2208 isolate->logger()->LogExistingFunction(
2209 shared, Handle<Code>(shared->code()));
2210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002211 }
2212
2213 target->set_context(*context);
2214 return *target;
2215}
2216
2217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002218RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002219 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002220 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002221 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002222 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002223 RUNTIME_ASSERT(num >= 0);
2224 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002225 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002226}
2227
2228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002229MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2230 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002231 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002232 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002233 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002235 }
2236 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002237 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002238}
2239
2240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002241RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002242 NoHandleAllocation ha;
2243 ASSERT(args.length() == 2);
2244
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002245 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002246 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002247 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002248
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002249 uint32_t i = 0;
2250 if (index->IsSmi()) {
2251 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002252 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002253 i = value;
2254 } else {
2255 ASSERT(index->IsHeapNumber());
2256 double value = HeapNumber::cast(index)->value();
2257 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002258 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002259
2260 // Flatten the string. If someone wants to get a char at an index
2261 // in a cons string, it is likely that more indices will be
2262 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002263 Object* flat;
2264 { MaybeObject* maybe_flat = subject->TryFlatten();
2265 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2266 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002267 subject = String::cast(flat);
2268
2269 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002270 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002271 }
2272
2273 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002274}
2275
2276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002277RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002278 NoHandleAllocation ha;
2279 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002280 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002281}
2282
lrn@chromium.org25156de2010-04-06 13:10:27 +00002283
2284class FixedArrayBuilder {
2285 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002286 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2287 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002288 length_(0),
2289 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 // Require a non-zero initial size. Ensures that doubling the size to
2291 // extend the array will work.
2292 ASSERT(initial_capacity > 0);
2293 }
2294
2295 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2296 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002297 length_(0),
2298 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002299 // Require a non-zero initial size. Ensures that doubling the size to
2300 // extend the array will work.
2301 ASSERT(backing_store->length() > 0);
2302 }
2303
2304 bool HasCapacity(int elements) {
2305 int length = array_->length();
2306 int required_length = length_ + elements;
2307 return (length >= required_length);
2308 }
2309
2310 void EnsureCapacity(int elements) {
2311 int length = array_->length();
2312 int required_length = length_ + elements;
2313 if (length < required_length) {
2314 int new_length = length;
2315 do {
2316 new_length *= 2;
2317 } while (new_length < required_length);
2318 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002319 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002320 array_->CopyTo(0, *extended_array, 0, length_);
2321 array_ = extended_array;
2322 }
2323 }
2324
2325 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002326 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002327 ASSERT(length_ < capacity());
2328 array_->set(length_, value);
2329 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002330 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002331 }
2332
2333 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002334 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002335 ASSERT(length_ < capacity());
2336 array_->set(length_, value);
2337 length_++;
2338 }
2339
2340 Handle<FixedArray> array() {
2341 return array_;
2342 }
2343
2344 int length() {
2345 return length_;
2346 }
2347
2348 int capacity() {
2349 return array_->length();
2350 }
2351
2352 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002353 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002354 result_array->set_length(Smi::FromInt(length_));
2355 return result_array;
2356 }
2357
2358 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002359 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002360 target_array->set_length(Smi::FromInt(length_));
2361 return target_array;
2362 }
2363
2364 private:
2365 Handle<FixedArray> array_;
2366 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002367 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002368};
2369
2370
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002371// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002372const int kStringBuilderConcatHelperLengthBits = 11;
2373const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374
2375template <typename schar>
2376static inline void StringBuilderConcatHelper(String*,
2377 schar*,
2378 FixedArray*,
2379 int);
2380
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2382 StringBuilderSubstringLength;
2383typedef BitField<int,
2384 kStringBuilderConcatHelperLengthBits,
2385 kStringBuilderConcatHelperPositionBits>
2386 StringBuilderSubstringPosition;
2387
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388
2389class ReplacementStringBuilder {
2390 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002391 ReplacementStringBuilder(Heap* heap,
2392 Handle<String> subject,
2393 int estimated_part_count)
2394 : heap_(heap),
2395 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002396 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002397 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002398 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002399 // Require a non-zero initial size. Ensures that doubling the size to
2400 // extend the array will work.
2401 ASSERT(estimated_part_count > 0);
2402 }
2403
lrn@chromium.org25156de2010-04-06 13:10:27 +00002404 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2405 int from,
2406 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002407 ASSERT(from >= 0);
2408 int length = to - from;
2409 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002410 if (StringBuilderSubstringLength::is_valid(length) &&
2411 StringBuilderSubstringPosition::is_valid(from)) {
2412 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2413 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002414 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002416 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002417 builder->Add(Smi::FromInt(-length));
2418 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002419 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002420 }
2421
2422
2423 void EnsureCapacity(int elements) {
2424 array_builder_.EnsureCapacity(elements);
2425 }
2426
2427
2428 void AddSubjectSlice(int from, int to) {
2429 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002430 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002431 }
2432
2433
2434 void AddString(Handle<String> string) {
2435 int length = string->length();
2436 ASSERT(length > 0);
2437 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002438 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 is_ascii_ = false;
2440 }
2441 IncrementCharacterCount(length);
2442 }
2443
2444
2445 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002446 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002447 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 }
2449
2450 Handle<String> joined_string;
2451 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002452 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002453 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002454 char* char_buffer = seq->GetChars();
2455 StringBuilderConcatHelper(*subject_,
2456 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002457 *array_builder_.array(),
2458 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002459 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002460 } else {
2461 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002462 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002464 uc16* char_buffer = seq->GetChars();
2465 StringBuilderConcatHelper(*subject_,
2466 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002467 *array_builder_.array(),
2468 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002469 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002470 }
2471 return joined_string;
2472 }
2473
2474
2475 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002476 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002477 V8::FatalProcessOutOfMemory("String.replace result too large.");
2478 }
2479 character_count_ += by;
2480 }
2481
lrn@chromium.org25156de2010-04-06 13:10:27 +00002482 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002483 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002484 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002485
lrn@chromium.org25156de2010-04-06 13:10:27 +00002486 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002487 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2488 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002489 }
2490
2491
ager@chromium.org04921a82011-06-27 13:21:41 +00002492 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2493 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002494 }
2495
2496
2497 void AddElement(Object* element) {
2498 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002499 ASSERT(array_builder_.capacity() > array_builder_.length());
2500 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002501 }
2502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002503 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002504 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002505 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002506 int character_count_;
2507 bool is_ascii_;
2508};
2509
2510
2511class CompiledReplacement {
2512 public:
2513 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002514 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002515
2516 void Compile(Handle<String> replacement,
2517 int capture_count,
2518 int subject_length);
2519
2520 void Apply(ReplacementStringBuilder* builder,
2521 int match_from,
2522 int match_to,
2523 Handle<JSArray> last_match_info);
2524
2525 // Number of distinct parts of the replacement pattern.
2526 int parts() {
2527 return parts_.length();
2528 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002529
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002530 bool simple_hint() {
2531 return simple_hint_;
2532 }
2533
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002534 private:
2535 enum PartType {
2536 SUBJECT_PREFIX = 1,
2537 SUBJECT_SUFFIX,
2538 SUBJECT_CAPTURE,
2539 REPLACEMENT_SUBSTRING,
2540 REPLACEMENT_STRING,
2541
2542 NUMBER_OF_PART_TYPES
2543 };
2544
2545 struct ReplacementPart {
2546 static inline ReplacementPart SubjectMatch() {
2547 return ReplacementPart(SUBJECT_CAPTURE, 0);
2548 }
2549 static inline ReplacementPart SubjectCapture(int capture_index) {
2550 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2551 }
2552 static inline ReplacementPart SubjectPrefix() {
2553 return ReplacementPart(SUBJECT_PREFIX, 0);
2554 }
2555 static inline ReplacementPart SubjectSuffix(int subject_length) {
2556 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2557 }
2558 static inline ReplacementPart ReplacementString() {
2559 return ReplacementPart(REPLACEMENT_STRING, 0);
2560 }
2561 static inline ReplacementPart ReplacementSubString(int from, int to) {
2562 ASSERT(from >= 0);
2563 ASSERT(to > from);
2564 return ReplacementPart(-from, to);
2565 }
2566
2567 // If tag <= 0 then it is the negation of a start index of a substring of
2568 // the replacement pattern, otherwise it's a value from PartType.
2569 ReplacementPart(int tag, int data)
2570 : tag(tag), data(data) {
2571 // Must be non-positive or a PartType value.
2572 ASSERT(tag < NUMBER_OF_PART_TYPES);
2573 }
2574 // Either a value of PartType or a non-positive number that is
2575 // the negation of an index into the replacement string.
2576 int tag;
2577 // The data value's interpretation depends on the value of tag:
2578 // tag == SUBJECT_PREFIX ||
2579 // tag == SUBJECT_SUFFIX: data is unused.
2580 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2581 // tag == REPLACEMENT_SUBSTRING ||
2582 // tag == REPLACEMENT_STRING: data is index into array of substrings
2583 // of the replacement string.
2584 // tag <= 0: Temporary representation of the substring of the replacement
2585 // string ranging over -tag .. data.
2586 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2587 // substring objects.
2588 int data;
2589 };
2590
2591 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002592 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002593 Vector<Char> characters,
2594 int capture_count,
2595 int subject_length) {
2596 int length = characters.length();
2597 int last = 0;
2598 for (int i = 0; i < length; i++) {
2599 Char c = characters[i];
2600 if (c == '$') {
2601 int next_index = i + 1;
2602 if (next_index == length) { // No next character!
2603 break;
2604 }
2605 Char c2 = characters[next_index];
2606 switch (c2) {
2607 case '$':
2608 if (i > last) {
2609 // There is a substring before. Include the first "$".
2610 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2611 last = next_index + 1; // Continue after the second "$".
2612 } else {
2613 // Let the next substring start with the second "$".
2614 last = next_index;
2615 }
2616 i = next_index;
2617 break;
2618 case '`':
2619 if (i > last) {
2620 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2621 }
2622 parts->Add(ReplacementPart::SubjectPrefix());
2623 i = next_index;
2624 last = i + 1;
2625 break;
2626 case '\'':
2627 if (i > last) {
2628 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2629 }
2630 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2631 i = next_index;
2632 last = i + 1;
2633 break;
2634 case '&':
2635 if (i > last) {
2636 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2637 }
2638 parts->Add(ReplacementPart::SubjectMatch());
2639 i = next_index;
2640 last = i + 1;
2641 break;
2642 case '0':
2643 case '1':
2644 case '2':
2645 case '3':
2646 case '4':
2647 case '5':
2648 case '6':
2649 case '7':
2650 case '8':
2651 case '9': {
2652 int capture_ref = c2 - '0';
2653 if (capture_ref > capture_count) {
2654 i = next_index;
2655 continue;
2656 }
2657 int second_digit_index = next_index + 1;
2658 if (second_digit_index < length) {
2659 // Peek ahead to see if we have two digits.
2660 Char c3 = characters[second_digit_index];
2661 if ('0' <= c3 && c3 <= '9') { // Double digits.
2662 int double_digit_ref = capture_ref * 10 + c3 - '0';
2663 if (double_digit_ref <= capture_count) {
2664 next_index = second_digit_index;
2665 capture_ref = double_digit_ref;
2666 }
2667 }
2668 }
2669 if (capture_ref > 0) {
2670 if (i > last) {
2671 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2672 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002673 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002674 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2675 last = next_index + 1;
2676 }
2677 i = next_index;
2678 break;
2679 }
2680 default:
2681 i = next_index;
2682 break;
2683 }
2684 }
2685 }
2686 if (length > last) {
2687 if (last == 0) {
2688 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002689 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002690 } else {
2691 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2692 }
2693 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002694 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002695 }
2696
2697 ZoneList<ReplacementPart> parts_;
2698 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002699 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002700};
2701
2702
2703void CompiledReplacement::Compile(Handle<String> replacement,
2704 int capture_count,
2705 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002706 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002707 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002708 String::FlatContent content = replacement->GetFlatContent();
2709 ASSERT(content.IsFlat());
2710 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002711 simple_hint_ = ParseReplacementPattern(&parts_,
2712 content.ToAsciiVector(),
2713 capture_count,
2714 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002715 } else {
2716 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002717 simple_hint_ = ParseReplacementPattern(&parts_,
2718 content.ToUC16Vector(),
2719 capture_count,
2720 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002721 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002722 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002724 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002725 int substring_index = 0;
2726 for (int i = 0, n = parts_.length(); i < n; i++) {
2727 int tag = parts_[i].tag;
2728 if (tag <= 0) { // A replacement string slice.
2729 int from = -tag;
2730 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002731 replacement_substrings_.Add(
2732 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002733 parts_[i].tag = REPLACEMENT_SUBSTRING;
2734 parts_[i].data = substring_index;
2735 substring_index++;
2736 } else if (tag == REPLACEMENT_STRING) {
2737 replacement_substrings_.Add(replacement);
2738 parts_[i].data = substring_index;
2739 substring_index++;
2740 }
2741 }
2742}
2743
2744
2745void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2746 int match_from,
2747 int match_to,
2748 Handle<JSArray> last_match_info) {
2749 for (int i = 0, n = parts_.length(); i < n; i++) {
2750 ReplacementPart part = parts_[i];
2751 switch (part.tag) {
2752 case SUBJECT_PREFIX:
2753 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2754 break;
2755 case SUBJECT_SUFFIX: {
2756 int subject_length = part.data;
2757 if (match_to < subject_length) {
2758 builder->AddSubjectSlice(match_to, subject_length);
2759 }
2760 break;
2761 }
2762 case SUBJECT_CAPTURE: {
2763 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002764 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002765 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2766 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2767 if (from >= 0 && to > from) {
2768 builder->AddSubjectSlice(from, to);
2769 }
2770 break;
2771 }
2772 case REPLACEMENT_SUBSTRING:
2773 case REPLACEMENT_STRING:
2774 builder->AddString(replacement_substrings_[part.data]);
2775 break;
2776 default:
2777 UNREACHABLE();
2778 }
2779 }
2780}
2781
2782
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002783void FindAsciiStringIndices(Vector<const char> subject,
2784 char pattern,
2785 ZoneList<int>* indices,
2786 unsigned int limit) {
2787 ASSERT(limit > 0);
2788 // Collect indices of pattern in subject using memchr.
2789 // Stop after finding at most limit values.
2790 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2791 const char* subject_end = subject_start + subject.length();
2792 const char* pos = subject_start;
2793 while (limit > 0) {
2794 pos = reinterpret_cast<const char*>(
2795 memchr(pos, pattern, subject_end - pos));
2796 if (pos == NULL) return;
2797 indices->Add(static_cast<int>(pos - subject_start));
2798 pos++;
2799 limit--;
2800 }
2801}
2802
2803
2804template <typename SubjectChar, typename PatternChar>
2805void FindStringIndices(Isolate* isolate,
2806 Vector<const SubjectChar> subject,
2807 Vector<const PatternChar> pattern,
2808 ZoneList<int>* indices,
2809 unsigned int limit) {
2810 ASSERT(limit > 0);
2811 // Collect indices of pattern in subject.
2812 // Stop after finding at most limit values.
2813 int pattern_length = pattern.length();
2814 int index = 0;
2815 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2816 while (limit > 0) {
2817 index = search.Search(subject, index);
2818 if (index < 0) return;
2819 indices->Add(index);
2820 index += pattern_length;
2821 limit--;
2822 }
2823}
2824
2825
2826void FindStringIndicesDispatch(Isolate* isolate,
2827 String* subject,
2828 String* pattern,
2829 ZoneList<int>* indices,
2830 unsigned int limit) {
2831 {
2832 AssertNoAllocation no_gc;
2833 String::FlatContent subject_content = subject->GetFlatContent();
2834 String::FlatContent pattern_content = pattern->GetFlatContent();
2835 ASSERT(subject_content.IsFlat());
2836 ASSERT(pattern_content.IsFlat());
2837 if (subject_content.IsAscii()) {
2838 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2839 if (pattern_content.IsAscii()) {
2840 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2841 if (pattern_vector.length() == 1) {
2842 FindAsciiStringIndices(subject_vector,
2843 pattern_vector[0],
2844 indices,
2845 limit);
2846 } else {
2847 FindStringIndices(isolate,
2848 subject_vector,
2849 pattern_vector,
2850 indices,
2851 limit);
2852 }
2853 } else {
2854 FindStringIndices(isolate,
2855 subject_vector,
2856 pattern_content.ToUC16Vector(),
2857 indices,
2858 limit);
2859 }
2860 } else {
2861 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002862 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002863 FindStringIndices(isolate,
2864 subject_vector,
2865 pattern_content.ToAsciiVector(),
2866 indices,
2867 limit);
2868 } else {
2869 FindStringIndices(isolate,
2870 subject_vector,
2871 pattern_content.ToUC16Vector(),
2872 indices,
2873 limit);
2874 }
2875 }
2876 }
2877}
2878
2879
2880template<typename ResultSeqString>
2881MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2882 Isolate* isolate,
2883 Handle<String> subject,
2884 Handle<JSRegExp> pattern_regexp,
2885 Handle<String> replacement) {
2886 ASSERT(subject->IsFlat());
2887 ASSERT(replacement->IsFlat());
2888
2889 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2890 ZoneList<int> indices(8);
2891 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2892 String* pattern =
2893 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2894 int subject_len = subject->length();
2895 int pattern_len = pattern->length();
2896 int replacement_len = replacement->length();
2897
2898 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2899
2900 int matches = indices.length();
2901 if (matches == 0) return *subject;
2902
2903 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2904 int subject_pos = 0;
2905 int result_pos = 0;
2906
2907 Handle<ResultSeqString> result;
2908 if (ResultSeqString::kHasAsciiEncoding) {
2909 result = Handle<ResultSeqString>::cast(
2910 isolate->factory()->NewRawAsciiString(result_len));
2911 } else {
2912 result = Handle<ResultSeqString>::cast(
2913 isolate->factory()->NewRawTwoByteString(result_len));
2914 }
2915
2916 for (int i = 0; i < matches; i++) {
2917 // Copy non-matched subject content.
2918 if (subject_pos < indices.at(i)) {
2919 String::WriteToFlat(*subject,
2920 result->GetChars() + result_pos,
2921 subject_pos,
2922 indices.at(i));
2923 result_pos += indices.at(i) - subject_pos;
2924 }
2925
2926 // Replace match.
2927 if (replacement_len > 0) {
2928 String::WriteToFlat(*replacement,
2929 result->GetChars() + result_pos,
2930 0,
2931 replacement_len);
2932 result_pos += replacement_len;
2933 }
2934
2935 subject_pos = indices.at(i) + pattern_len;
2936 }
2937 // Add remaining subject content at the end.
2938 if (subject_pos < subject_len) {
2939 String::WriteToFlat(*subject,
2940 result->GetChars() + result_pos,
2941 subject_pos,
2942 subject_len);
2943 }
2944 return *result;
2945}
2946
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002947
lrn@chromium.org303ada72010-10-27 09:33:13 +00002948MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002949 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002950 String* subject,
2951 JSRegExp* regexp,
2952 String* replacement,
2953 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002954 ASSERT(subject->IsFlat());
2955 ASSERT(replacement->IsFlat());
2956
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002957 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002958
2959 int length = subject->length();
2960 Handle<String> subject_handle(subject);
2961 Handle<JSRegExp> regexp_handle(regexp);
2962 Handle<String> replacement_handle(replacement);
2963 Handle<JSArray> last_match_info_handle(last_match_info);
2964 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2965 subject_handle,
2966 0,
2967 last_match_info_handle);
2968 if (match.is_null()) {
2969 return Failure::Exception();
2970 }
2971 if (match->IsNull()) {
2972 return *subject_handle;
2973 }
2974
2975 int capture_count = regexp_handle->CaptureCount();
2976
2977 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002978 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002979 CompiledReplacement compiled_replacement;
2980 compiled_replacement.Compile(replacement_handle,
2981 capture_count,
2982 length);
2983
2984 bool is_global = regexp_handle->GetFlags().is_global();
2985
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002986 // Shortcut for simple non-regexp global replacements
2987 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002988 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002989 compiled_replacement.simple_hint()) {
2990 if (subject_handle->HasOnlyAsciiChars() &&
2991 replacement_handle->HasOnlyAsciiChars()) {
2992 return StringReplaceStringWithString<SeqAsciiString>(
2993 isolate, subject_handle, regexp_handle, replacement_handle);
2994 } else {
2995 return StringReplaceStringWithString<SeqTwoByteString>(
2996 isolate, subject_handle, regexp_handle, replacement_handle);
2997 }
2998 }
2999
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003000 // Guessing the number of parts that the final result string is built
3001 // from. Global regexps can match any number of times, so we guess
3002 // conservatively.
3003 int expected_parts =
3004 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003005 ReplacementStringBuilder builder(isolate->heap(),
3006 subject_handle,
3007 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003008
3009 // Index of end of last match.
3010 int prev = 0;
3011
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003012 // Number of parts added by compiled replacement plus preceeding
3013 // string and possibly suffix after last match. It is possible for
3014 // all components to use two elements when encoded as two smis.
3015 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003016 bool matched = true;
3017 do {
3018 ASSERT(last_match_info_handle->HasFastElements());
3019 // Increase the capacity of the builder before entering local handle-scope,
3020 // so its internal buffer can safely allocate a new handle if it grows.
3021 builder.EnsureCapacity(parts_added_per_loop);
3022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003023 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003024 int start, end;
3025 {
3026 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003027 FixedArray* match_info_array =
3028 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003029
3030 ASSERT_EQ(capture_count * 2 + 2,
3031 RegExpImpl::GetLastCaptureCount(match_info_array));
3032 start = RegExpImpl::GetCapture(match_info_array, 0);
3033 end = RegExpImpl::GetCapture(match_info_array, 1);
3034 }
3035
3036 if (prev < start) {
3037 builder.AddSubjectSlice(prev, start);
3038 }
3039 compiled_replacement.Apply(&builder,
3040 start,
3041 end,
3042 last_match_info_handle);
3043 prev = end;
3044
3045 // Only continue checking for global regexps.
3046 if (!is_global) break;
3047
3048 // Continue from where the match ended, unless it was an empty match.
3049 int next = end;
3050 if (start == end) {
3051 next = end + 1;
3052 if (next > length) break;
3053 }
3054
3055 match = RegExpImpl::Exec(regexp_handle,
3056 subject_handle,
3057 next,
3058 last_match_info_handle);
3059 if (match.is_null()) {
3060 return Failure::Exception();
3061 }
3062 matched = !match->IsNull();
3063 } while (matched);
3064
3065 if (prev < length) {
3066 builder.AddSubjectSlice(prev, length);
3067 }
3068
3069 return *(builder.ToString());
3070}
3071
3072
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003073template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003074MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003075 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003076 String* subject,
3077 JSRegExp* regexp,
3078 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003079 ASSERT(subject->IsFlat());
3080
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003081 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003082
3083 Handle<String> subject_handle(subject);
3084 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003085
3086 // Shortcut for simple non-regexp global replacements
3087 if (regexp_handle->GetFlags().is_global() &&
3088 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3089 Handle<String> empty_string_handle(HEAP->empty_string());
3090 if (subject_handle->HasOnlyAsciiChars()) {
3091 return StringReplaceStringWithString<SeqAsciiString>(
3092 isolate, subject_handle, regexp_handle, empty_string_handle);
3093 } else {
3094 return StringReplaceStringWithString<SeqTwoByteString>(
3095 isolate, subject_handle, regexp_handle, empty_string_handle);
3096 }
3097 }
3098
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003099 Handle<JSArray> last_match_info_handle(last_match_info);
3100 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3101 subject_handle,
3102 0,
3103 last_match_info_handle);
3104 if (match.is_null()) return Failure::Exception();
3105 if (match->IsNull()) return *subject_handle;
3106
3107 ASSERT(last_match_info_handle->HasFastElements());
3108
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003109 int start, end;
3110 {
3111 AssertNoAllocation match_info_array_is_not_in_a_handle;
3112 FixedArray* match_info_array =
3113 FixedArray::cast(last_match_info_handle->elements());
3114
3115 start = RegExpImpl::GetCapture(match_info_array, 0);
3116 end = RegExpImpl::GetCapture(match_info_array, 1);
3117 }
3118
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003119 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003120 int new_length = length - (end - start);
3121 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003122 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003123 }
3124 Handle<ResultSeqString> answer;
3125 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003126 answer = Handle<ResultSeqString>::cast(
3127 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003128 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003129 answer = Handle<ResultSeqString>::cast(
3130 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003131 }
3132
3133 // If the regexp isn't global, only match once.
3134 if (!regexp_handle->GetFlags().is_global()) {
3135 if (start > 0) {
3136 String::WriteToFlat(*subject_handle,
3137 answer->GetChars(),
3138 0,
3139 start);
3140 }
3141 if (end < length) {
3142 String::WriteToFlat(*subject_handle,
3143 answer->GetChars() + start,
3144 end,
3145 length);
3146 }
3147 return *answer;
3148 }
3149
3150 int prev = 0; // Index of end of last match.
3151 int next = 0; // Start of next search (prev unless last match was empty).
3152 int position = 0;
3153
3154 do {
3155 if (prev < start) {
3156 // Add substring subject[prev;start] to answer string.
3157 String::WriteToFlat(*subject_handle,
3158 answer->GetChars() + position,
3159 prev,
3160 start);
3161 position += start - prev;
3162 }
3163 prev = end;
3164 next = end;
3165 // Continue from where the match ended, unless it was an empty match.
3166 if (start == end) {
3167 next++;
3168 if (next > length) break;
3169 }
3170 match = RegExpImpl::Exec(regexp_handle,
3171 subject_handle,
3172 next,
3173 last_match_info_handle);
3174 if (match.is_null()) return Failure::Exception();
3175 if (match->IsNull()) break;
3176
3177 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003178 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003179 {
3180 AssertNoAllocation match_info_array_is_not_in_a_handle;
3181 FixedArray* match_info_array =
3182 FixedArray::cast(last_match_info_handle->elements());
3183 start = RegExpImpl::GetCapture(match_info_array, 0);
3184 end = RegExpImpl::GetCapture(match_info_array, 1);
3185 }
3186 } while (true);
3187
3188 if (prev < length) {
3189 // Add substring subject[prev;length] to answer string.
3190 String::WriteToFlat(*subject_handle,
3191 answer->GetChars() + position,
3192 prev,
3193 length);
3194 position += length - prev;
3195 }
3196
3197 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003198 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003199 }
3200
3201 // Shorten string and fill
3202 int string_size = ResultSeqString::SizeFor(position);
3203 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3204 int delta = allocated_string_size - string_size;
3205
3206 answer->set_length(position);
3207 if (delta == 0) return *answer;
3208
3209 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003210 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003211 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003212 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003213 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003214
3215 return *answer;
3216}
3217
3218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003219RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003220 ASSERT(args.length() == 4);
3221
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003222 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003223 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003224 Object* flat_subject;
3225 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3226 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3227 return maybe_flat_subject;
3228 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003229 }
3230 subject = String::cast(flat_subject);
3231 }
3232
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003233 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003234 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003235 Object* flat_replacement;
3236 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3237 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3238 return maybe_flat_replacement;
3239 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003240 }
3241 replacement = String::cast(flat_replacement);
3242 }
3243
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003244 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3245 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003246
3247 ASSERT(last_match_info->HasFastElements());
3248
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003249 if (replacement->length() == 0) {
3250 if (subject->HasOnlyAsciiChars()) {
3251 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003252 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003253 } else {
3254 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003255 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003256 }
3257 }
3258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003259 return StringReplaceRegExpWithString(isolate,
3260 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003261 regexp,
3262 replacement,
3263 last_match_info);
3264}
3265
3266
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003267Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3268 Handle<String> subject,
3269 Handle<String> search,
3270 Handle<String> replace,
3271 bool* found,
3272 int recursion_limit) {
3273 if (recursion_limit == 0) return Handle<String>::null();
3274 if (subject->IsConsString()) {
3275 ConsString* cons = ConsString::cast(*subject);
3276 Handle<String> first = Handle<String>(cons->first());
3277 Handle<String> second = Handle<String>(cons->second());
3278 Handle<String> new_first =
3279 StringReplaceOneCharWithString(isolate,
3280 first,
3281 search,
3282 replace,
3283 found,
3284 recursion_limit - 1);
3285 if (*found) return isolate->factory()->NewConsString(new_first, second);
3286 if (new_first.is_null()) return new_first;
3287
3288 Handle<String> new_second =
3289 StringReplaceOneCharWithString(isolate,
3290 second,
3291 search,
3292 replace,
3293 found,
3294 recursion_limit - 1);
3295 if (*found) return isolate->factory()->NewConsString(first, new_second);
3296 if (new_second.is_null()) return new_second;
3297
3298 return subject;
3299 } else {
3300 int index = StringMatch(isolate, subject, search, 0);
3301 if (index == -1) return subject;
3302 *found = true;
3303 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3304 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3305 Handle<String> second =
3306 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3307 return isolate->factory()->NewConsString(cons1, second);
3308 }
3309}
3310
3311
3312RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3313 ASSERT(args.length() == 3);
3314 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003315 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3316 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3317 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003318
3319 // If the cons string tree is too deep, we simply abort the recursion and
3320 // retry with a flattened subject string.
3321 const int kRecursionLimit = 0x1000;
3322 bool found = false;
3323 Handle<String> result =
3324 Runtime::StringReplaceOneCharWithString(isolate,
3325 subject,
3326 search,
3327 replace,
3328 &found,
3329 kRecursionLimit);
3330 if (!result.is_null()) return *result;
3331 return *Runtime::StringReplaceOneCharWithString(isolate,
3332 FlattenGetString(subject),
3333 search,
3334 replace,
3335 &found,
3336 kRecursionLimit);
3337}
3338
3339
ager@chromium.org7c537e22008-10-16 08:43:32 +00003340// Perform string match of pattern on subject, starting at start index.
3341// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003342// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003343int Runtime::StringMatch(Isolate* isolate,
3344 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003345 Handle<String> pat,
3346 int start_index) {
3347 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003348 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003349
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003350 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003351 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003352
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003353 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003354 if (start_index + pattern_length > subject_length) return -1;
3355
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003356 if (!sub->IsFlat()) FlattenString(sub);
3357 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003358
ager@chromium.org7c537e22008-10-16 08:43:32 +00003359 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003360 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003361 String::FlatContent seq_sub = sub->GetFlatContent();
3362 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003363
ager@chromium.org7c537e22008-10-16 08:43:32 +00003364 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003365 if (seq_pat.IsAscii()) {
3366 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3367 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003368 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003369 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003370 pat_vector,
3371 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003372 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003373 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003375 pat_vector,
3376 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003377 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003378 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3379 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003380 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003381 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003382 pat_vector,
3383 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003384 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003385 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003386 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003387 pat_vector,
3388 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003389}
3390
3391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003392RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003393 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003394 ASSERT(args.length() == 3);
3395
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003396 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3397 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003398
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003399 Object* index = args[2];
3400 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003401 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003402
ager@chromium.org870a0b62008-11-04 11:43:05 +00003403 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003404 int position =
3405 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003406 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407}
3408
3409
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003410template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003411static int StringMatchBackwards(Vector<const schar> subject,
3412 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003413 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003414 int pattern_length = pattern.length();
3415 ASSERT(pattern_length >= 1);
3416 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003417
3418 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003419 for (int i = 0; i < pattern_length; i++) {
3420 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003421 if (c > String::kMaxAsciiCharCode) {
3422 return -1;
3423 }
3424 }
3425 }
3426
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003427 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003428 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003429 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003431 while (j < pattern_length) {
3432 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003433 break;
3434 }
3435 j++;
3436 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003437 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003438 return i;
3439 }
3440 }
3441 return -1;
3442}
3443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003444RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003445 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003446 ASSERT(args.length() == 3);
3447
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003448 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3449 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003451 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003452 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003453 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003455 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003456 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003458 if (start_index + pat_length > sub_length) {
3459 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003460 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003461
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003462 if (pat_length == 0) {
3463 return Smi::FromInt(start_index);
3464 }
3465
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003466 if (!sub->IsFlat()) FlattenString(sub);
3467 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003468
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003469 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003470 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3471
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003472 String::FlatContent sub_content = sub->GetFlatContent();
3473 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003474
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003475 if (pat_content.IsAscii()) {
3476 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3477 if (sub_content.IsAscii()) {
3478 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003479 pat_vector,
3480 start_index);
3481 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003482 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003483 pat_vector,
3484 start_index);
3485 }
3486 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003487 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3488 if (sub_content.IsAscii()) {
3489 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003490 pat_vector,
3491 start_index);
3492 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003493 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003494 pat_vector,
3495 start_index);
3496 }
3497 }
3498
3499 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003500}
3501
3502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003503RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003504 NoHandleAllocation ha;
3505 ASSERT(args.length() == 2);
3506
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003507 CONVERT_ARG_CHECKED(String, str1, 0);
3508 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003509
3510 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003511 int str1_length = str1->length();
3512 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513
3514 // Decide trivial cases without flattening.
3515 if (str1_length == 0) {
3516 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3517 return Smi::FromInt(-str2_length);
3518 } else {
3519 if (str2_length == 0) return Smi::FromInt(str1_length);
3520 }
3521
3522 int end = str1_length < str2_length ? str1_length : str2_length;
3523
3524 // No need to flatten if we are going to find the answer on the first
3525 // character. At this point we know there is at least one character
3526 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003527 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003528 if (d != 0) return Smi::FromInt(d);
3529
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003530 str1->TryFlatten();
3531 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003532
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003533 StringInputBuffer& buf1 =
3534 *isolate->runtime_state()->string_locale_compare_buf1();
3535 StringInputBuffer& buf2 =
3536 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537
3538 buf1.Reset(str1);
3539 buf2.Reset(str2);
3540
3541 for (int i = 0; i < end; i++) {
3542 uint16_t char1 = buf1.GetNext();
3543 uint16_t char2 = buf2.GetNext();
3544 if (char1 != char2) return Smi::FromInt(char1 - char2);
3545 }
3546
3547 return Smi::FromInt(str1_length - str2_length);
3548}
3549
3550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003551RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003552 NoHandleAllocation ha;
3553 ASSERT(args.length() == 3);
3554
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003555 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003556 int start, end;
3557 // We have a fast integer-only case here to avoid a conversion to double in
3558 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003559 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3560 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3561 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3562 start = from_number;
3563 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003564 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003565 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3566 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003567 start = FastD2I(from_number);
3568 end = FastD2I(to_number);
3569 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003570 RUNTIME_ASSERT(end >= start);
3571 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003572 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003573 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003574 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003575}
3576
3577
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003578RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003579 ASSERT_EQ(3, args.length());
3580
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003581 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3582 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3583 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003584 HandleScope handles;
3585
3586 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3587
3588 if (match.is_null()) {
3589 return Failure::Exception();
3590 }
3591 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003592 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003593 }
3594 int length = subject->length();
3595
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003596 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003597 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003598 int start;
3599 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003600 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003601 {
3602 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003603 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003604 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3605 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3606 }
3607 offsets.Add(start);
3608 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003609 if (start == end) if (++end > length) break;
3610 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003611 if (match.is_null()) {
3612 return Failure::Exception();
3613 }
3614 } while (!match->IsNull());
3615 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003617 Handle<String> substring = isolate->factory()->
3618 NewSubString(subject, offsets.at(0), offsets.at(1));
3619 elements->set(0, *substring);
3620 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003621 int from = offsets.at(i * 2);
3622 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003623 Handle<String> substring = isolate->factory()->
3624 NewProperSubString(subject, from, to);
3625 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003626 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003628 result->set_length(Smi::FromInt(matches));
3629 return *result;
3630}
3631
3632
lrn@chromium.org25156de2010-04-06 13:10:27 +00003633// Two smis before and after the match, for very long strings.
3634const int kMaxBuilderEntriesPerRegExpMatch = 5;
3635
3636
3637static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3638 Handle<JSArray> last_match_info,
3639 int match_start,
3640 int match_end) {
3641 // Fill last_match_info with a single capture.
3642 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3643 AssertNoAllocation no_gc;
3644 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3645 RegExpImpl::SetLastCaptureCount(elements, 2);
3646 RegExpImpl::SetLastInput(elements, *subject);
3647 RegExpImpl::SetLastSubject(elements, *subject);
3648 RegExpImpl::SetCapture(elements, 0, match_start);
3649 RegExpImpl::SetCapture(elements, 1, match_end);
3650}
3651
3652
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003653template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003654static bool SearchStringMultiple(Isolate* isolate,
3655 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003656 Vector<const PatternChar> pattern,
3657 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003658 FixedArrayBuilder* builder,
3659 int* match_pos) {
3660 int pos = *match_pos;
3661 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003662 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003663 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003664 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003665 while (pos <= max_search_start) {
3666 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3667 *match_pos = pos;
3668 return false;
3669 }
3670 // Position of end of previous match.
3671 int match_end = pos + pattern_length;
3672 int new_pos = search.Search(subject, match_end);
3673 if (new_pos >= 0) {
3674 // A match.
3675 if (new_pos > match_end) {
3676 ReplacementStringBuilder::AddSubjectSlice(builder,
3677 match_end,
3678 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003679 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003680 pos = new_pos;
3681 builder->Add(pattern_string);
3682 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003683 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003684 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003685 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003686
lrn@chromium.org25156de2010-04-06 13:10:27 +00003687 if (pos < max_search_start) {
3688 ReplacementStringBuilder::AddSubjectSlice(builder,
3689 pos + pattern_length,
3690 subject_length);
3691 }
3692 *match_pos = pos;
3693 return true;
3694}
3695
3696
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003697static bool SearchStringMultiple(Isolate* isolate,
3698 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003699 Handle<String> pattern,
3700 Handle<JSArray> last_match_info,
3701 FixedArrayBuilder* builder) {
3702 ASSERT(subject->IsFlat());
3703 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003704
3705 // Treating as if a previous match was before first character.
3706 int match_pos = -pattern->length();
3707
3708 for (;;) { // Break when search complete.
3709 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3710 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003711 String::FlatContent subject_content = subject->GetFlatContent();
3712 String::FlatContent pattern_content = pattern->GetFlatContent();
3713 if (subject_content.IsAscii()) {
3714 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3715 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003716 if (SearchStringMultiple(isolate,
3717 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003718 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003719 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003720 builder,
3721 &match_pos)) break;
3722 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003723 if (SearchStringMultiple(isolate,
3724 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003725 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003726 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003727 builder,
3728 &match_pos)) break;
3729 }
3730 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003731 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3732 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003733 if (SearchStringMultiple(isolate,
3734 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003735 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003736 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003737 builder,
3738 &match_pos)) break;
3739 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003740 if (SearchStringMultiple(isolate,
3741 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003742 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003743 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003744 builder,
3745 &match_pos)) break;
3746 }
3747 }
3748 }
3749
3750 if (match_pos >= 0) {
3751 SetLastMatchInfoNoCaptures(subject,
3752 last_match_info,
3753 match_pos,
3754 match_pos + pattern->length());
3755 return true;
3756 }
3757 return false; // No matches at all.
3758}
3759
3760
3761static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003762 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003763 Handle<String> subject,
3764 Handle<JSRegExp> regexp,
3765 Handle<JSArray> last_match_array,
3766 FixedArrayBuilder* builder) {
3767 ASSERT(subject->IsFlat());
3768 int match_start = -1;
3769 int match_end = 0;
3770 int pos = 0;
3771 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3772 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3773
ulan@chromium.org812308e2012-02-29 15:58:45 +00003774 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003775 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003776 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003777 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003778
3779 for (;;) { // Break on failure, return on exception.
3780 RegExpImpl::IrregexpResult result =
3781 RegExpImpl::IrregexpExecOnce(regexp,
3782 subject,
3783 pos,
3784 register_vector);
3785 if (result == RegExpImpl::RE_SUCCESS) {
3786 match_start = register_vector[0];
3787 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3788 if (match_end < match_start) {
3789 ReplacementStringBuilder::AddSubjectSlice(builder,
3790 match_end,
3791 match_start);
3792 }
3793 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003795 if (!first) {
3796 builder->Add(*isolate->factory()->NewProperSubString(subject,
3797 match_start,
3798 match_end));
3799 } else {
3800 builder->Add(*isolate->factory()->NewSubString(subject,
3801 match_start,
3802 match_end));
3803 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003804 if (match_start != match_end) {
3805 pos = match_end;
3806 } else {
3807 pos = match_end + 1;
3808 if (pos > subject_length) break;
3809 }
3810 } else if (result == RegExpImpl::RE_FAILURE) {
3811 break;
3812 } else {
3813 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3814 return result;
3815 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003816 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003817 }
3818
3819 if (match_start >= 0) {
3820 if (match_end < subject_length) {
3821 ReplacementStringBuilder::AddSubjectSlice(builder,
3822 match_end,
3823 subject_length);
3824 }
3825 SetLastMatchInfoNoCaptures(subject,
3826 last_match_array,
3827 match_start,
3828 match_end);
3829 return RegExpImpl::RE_SUCCESS;
3830 } else {
3831 return RegExpImpl::RE_FAILURE; // No matches at all.
3832 }
3833}
3834
3835
3836static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003837 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003838 Handle<String> subject,
3839 Handle<JSRegExp> regexp,
3840 Handle<JSArray> last_match_array,
3841 FixedArrayBuilder* builder) {
3842
3843 ASSERT(subject->IsFlat());
3844 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3845 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3846
ulan@chromium.org812308e2012-02-29 15:58:45 +00003847 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003848 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003849
3850 RegExpImpl::IrregexpResult result =
3851 RegExpImpl::IrregexpExecOnce(regexp,
3852 subject,
3853 0,
3854 register_vector);
3855
3856 int capture_count = regexp->CaptureCount();
3857 int subject_length = subject->length();
3858
3859 // Position to search from.
3860 int pos = 0;
3861 // End of previous match. Differs from pos if match was empty.
3862 int match_end = 0;
3863 if (result == RegExpImpl::RE_SUCCESS) {
3864 // Need to keep a copy of the previous match for creating last_match_info
3865 // at the end, so we have two vectors that we swap between.
ulan@chromium.org812308e2012-02-29 15:58:45 +00003866 OffsetsVector registers2(required_registers, isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003867 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003868 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003869 do {
3870 int match_start = register_vector[0];
3871 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3872 if (match_end < match_start) {
3873 ReplacementStringBuilder::AddSubjectSlice(builder,
3874 match_end,
3875 match_start);
3876 }
3877 match_end = register_vector[1];
3878
3879 {
3880 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003881 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003882 // Arguments array to replace function is match, captures, index and
3883 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003884 Handle<FixedArray> elements =
3885 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003886 Handle<String> match;
3887 if (!first) {
3888 match = isolate->factory()->NewProperSubString(subject,
3889 match_start,
3890 match_end);
3891 } else {
3892 match = isolate->factory()->NewSubString(subject,
3893 match_start,
3894 match_end);
3895 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003896 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003897 for (int i = 1; i <= capture_count; i++) {
3898 int start = register_vector[i * 2];
3899 if (start >= 0) {
3900 int end = register_vector[i * 2 + 1];
3901 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003902 Handle<String> substring;
3903 if (!first) {
3904 substring = isolate->factory()->NewProperSubString(subject,
3905 start,
3906 end);
3907 } else {
3908 substring = isolate->factory()->NewSubString(subject, start, end);
3909 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003910 elements->set(i, *substring);
3911 } else {
3912 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003913 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003914 }
3915 }
3916 elements->set(capture_count + 1, Smi::FromInt(match_start));
3917 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003918 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 }
3920 // Swap register vectors, so the last successful match is in
3921 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003922 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003923 prev_register_vector = register_vector;
3924 register_vector = tmp;
3925
3926 if (match_end > match_start) {
3927 pos = match_end;
3928 } else {
3929 pos = match_end + 1;
3930 if (pos > subject_length) {
3931 break;
3932 }
3933 }
3934
3935 result = RegExpImpl::IrregexpExecOnce(regexp,
3936 subject,
3937 pos,
3938 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003939 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003940 } while (result == RegExpImpl::RE_SUCCESS);
3941
3942 if (result != RegExpImpl::RE_EXCEPTION) {
3943 // Finished matching, with at least one match.
3944 if (match_end < subject_length) {
3945 ReplacementStringBuilder::AddSubjectSlice(builder,
3946 match_end,
3947 subject_length);
3948 }
3949
3950 int last_match_capture_count = (capture_count + 1) * 2;
3951 int last_match_array_size =
3952 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3953 last_match_array->EnsureSize(last_match_array_size);
3954 AssertNoAllocation no_gc;
3955 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3956 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3957 RegExpImpl::SetLastSubject(elements, *subject);
3958 RegExpImpl::SetLastInput(elements, *subject);
3959 for (int i = 0; i < last_match_capture_count; i++) {
3960 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3961 }
3962 return RegExpImpl::RE_SUCCESS;
3963 }
3964 }
3965 // No matches at all, return failure or exception result directly.
3966 return result;
3967}
3968
3969
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003970RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003971 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003972 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003973
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003974 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003975 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003976 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3977 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3978 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003979
3980 ASSERT(last_match_info->HasFastElements());
3981 ASSERT(regexp->GetFlags().is_global());
3982 Handle<FixedArray> result_elements;
3983 if (result_array->HasFastElements()) {
3984 result_elements =
3985 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003986 }
3987 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003988 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003989 }
3990 FixedArrayBuilder builder(result_elements);
3991
3992 if (regexp->TypeTag() == JSRegExp::ATOM) {
3993 Handle<String> pattern(
3994 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003995 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 if (SearchStringMultiple(isolate, subject, pattern,
3997 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003998 return *builder.ToJSArray(result_array);
3999 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004000 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004001 }
4002
4003 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4004
4005 RegExpImpl::IrregexpResult result;
4006 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 result = SearchRegExpNoCaptureMultiple(isolate,
4008 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004009 regexp,
4010 last_match_info,
4011 &builder);
4012 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004013 result = SearchRegExpMultiple(isolate,
4014 subject,
4015 regexp,
4016 last_match_info,
4017 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004018 }
4019 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004020 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004021 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4022 return Failure::Exception();
4023}
4024
4025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004026RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 NoHandleAllocation ha;
4028 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004029 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004030 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004031
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004032 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004033 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004034 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004035 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004036 // Character array used for conversion.
4037 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004038 return isolate->heap()->
4039 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004040 }
4041 }
4042
4043 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004044 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004046 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 }
4048 if (isinf(value)) {
4049 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004050 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004051 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004052 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004055 MaybeObject* result =
4056 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057 DeleteArray(str);
4058 return result;
4059}
4060
4061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004062RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 NoHandleAllocation ha;
4064 ASSERT(args.length() == 2);
4065
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004066 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004068 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 }
4070 if (isinf(value)) {
4071 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004072 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004074 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004076 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 int f = FastD2I(f_number);
4078 RUNTIME_ASSERT(f >= 0);
4079 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004080 MaybeObject* res =
4081 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004083 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084}
4085
4086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004087RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 NoHandleAllocation ha;
4089 ASSERT(args.length() == 2);
4090
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004091 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004093 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 }
4095 if (isinf(value)) {
4096 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004097 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004099 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004101 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 int f = FastD2I(f_number);
4103 RUNTIME_ASSERT(f >= -1 && f <= 20);
4104 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004105 MaybeObject* res =
4106 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004108 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109}
4110
4111
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004112RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 NoHandleAllocation ha;
4114 ASSERT(args.length() == 2);
4115
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004116 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004118 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 }
4120 if (isinf(value)) {
4121 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004122 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004124 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004125 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004126 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127 int f = FastD2I(f_number);
4128 RUNTIME_ASSERT(f >= 1 && f <= 21);
4129 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004130 MaybeObject* res =
4131 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004133 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134}
4135
4136
4137// Returns a single character string where first character equals
4138// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004139static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004140 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004141 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004142 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004143 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004144 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004145 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004146}
4147
4148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004149MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4150 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004151 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152 // Handle [] indexing on Strings
4153 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4155 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004156 }
4157
4158 // Handle [] indexing on String objects
4159 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004160 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4161 Handle<Object> result =
4162 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4163 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 }
4165
4166 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004167 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004168 }
4169
4170 return object->GetElement(index);
4171}
4172
4173
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004174MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4175 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004176 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004179 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004180 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004182 isolate->factory()->NewTypeError("non_object_property_load",
4183 HandleVector(args, 2));
4184 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 }
4186
4187 // Check if the given key is an array index.
4188 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004189 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004190 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191 }
4192
4193 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004194 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004196 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004198 bool has_pending_exception = false;
4199 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004200 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004202 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 }
4204
ager@chromium.org32912102009-01-16 10:38:43 +00004205 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206 // the element if so.
4207 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004208 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004210 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211 }
4212}
4213
4214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004215RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216 NoHandleAllocation ha;
4217 ASSERT(args.length() == 2);
4218
4219 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004220 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004221
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004222 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223}
4224
4225
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004226// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004227RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004228 NoHandleAllocation ha;
4229 ASSERT(args.length() == 2);
4230
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004231 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004232 // itself.
4233 //
4234 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004235 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004236 // global proxy object never has properties. This is the case
4237 // because the global proxy object forwards everything to its hidden
4238 // prototype including local lookups.
4239 //
4240 // Additionally, we need to make sure that we do not cache results
4241 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004242 if (args[0]->IsJSObject()) {
4243 if (!args[0]->IsJSGlobalProxy() &&
4244 !args[0]->IsAccessCheckNeeded() &&
4245 args[1]->IsString()) {
4246 JSObject* receiver = JSObject::cast(args[0]);
4247 String* key = String::cast(args[1]);
4248 if (receiver->HasFastProperties()) {
4249 // Attempt to use lookup cache.
4250 Map* receiver_map = receiver->map();
4251 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4252 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4253 if (offset != -1) {
4254 Object* value = receiver->FastPropertyAt(offset);
4255 return value->IsTheHole()
4256 ? isolate->heap()->undefined_value()
4257 : value;
4258 }
4259 // Lookup cache miss. Perform lookup and update the cache if
4260 // appropriate.
4261 LookupResult result(isolate);
4262 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004263 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004264 int offset = result.GetFieldIndex();
4265 keyed_lookup_cache->Update(receiver_map, key, offset);
4266 return receiver->FastPropertyAt(offset);
4267 }
4268 } else {
4269 // Attempt dictionary lookup.
4270 StringDictionary* dictionary = receiver->property_dictionary();
4271 int entry = dictionary->FindEntry(key);
4272 if ((entry != StringDictionary::kNotFound) &&
4273 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4274 Object* value = dictionary->ValueAt(entry);
4275 if (!receiver->IsGlobalObject()) return value;
4276 value = JSGlobalPropertyCell::cast(value)->value();
4277 if (!value->IsTheHole()) return value;
4278 // If value is the hole do the general lookup.
4279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004280 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004281 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4282 // JSObject without a string key. If the key is a Smi, check for a
4283 // definite out-of-bounds access to elements, which is a strong indicator
4284 // that subsequent accesses will also call the runtime. Proactively
4285 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4286 // doubles for those future calls in the case that the elements would
4287 // become FAST_DOUBLE_ELEMENTS.
4288 Handle<JSObject> js_object(args.at<JSObject>(0));
4289 ElementsKind elements_kind = js_object->GetElementsKind();
4290 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4291 elements_kind == FAST_DOUBLE_ELEMENTS) {
4292 FixedArrayBase* elements = js_object->elements();
4293 if (args.at<Smi>(1)->value() >= elements->length()) {
4294 MaybeObject* maybe_object = TransitionElements(js_object,
4295 FAST_ELEMENTS,
4296 isolate);
4297 if (maybe_object->IsFailure()) return maybe_object;
4298 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004299 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004300 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004301 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4302 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004303 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004304 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004305 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004306 if (index >= 0 && index < str->length()) {
4307 Handle<Object> result = GetCharAt(str, index);
4308 return *result;
4309 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004310 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004311
4312 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004313 return Runtime::GetObjectProperty(isolate,
4314 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004315 args.at<Object>(1));
4316}
4317
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004318
4319static bool IsValidAccessor(Handle<Object> obj) {
4320 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
4321}
4322
4323
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004324// Implements part of 8.12.9 DefineOwnProperty.
4325// There are 3 cases that lead here:
4326// Step 4b - define a new accessor property.
4327// Steps 9c & 12 - replace an existing data property with an accessor property.
4328// Step 12 - update an existing accessor property with an accessor or generic
4329// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004330RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004331 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004332 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004333 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004334 RUNTIME_ASSERT(!obj->IsNull());
4335 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4336 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
4337 RUNTIME_ASSERT(IsValidAccessor(getter));
4338 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
4339 RUNTIME_ASSERT(IsValidAccessor(setter));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004340 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00004341 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004342 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004343
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004344 // TODO(svenpanne) Define getter/setter/attributes in a single step.
4345 if (getter->IsNull() && setter->IsNull()) {
4346 JSArray* array;
4347 { MaybeObject* maybe_array = GetOwnProperty(isolate, obj, name);
4348 if (!maybe_array->To(&array)) return maybe_array;
4349 }
4350 Object* current = FixedArray::cast(array->elements())->get(GETTER_INDEX);
4351 getter = Handle<Object>(current, isolate);
4352 }
4353 if (!getter->IsNull()) {
4354 MaybeObject* ok =
4355 obj->DefineAccessor(*name, ACCESSOR_GETTER, *getter, attr);
4356 if (ok->IsFailure()) return ok;
4357 }
4358 if (!setter->IsNull()) {
4359 MaybeObject* ok =
4360 obj->DefineAccessor(*name, ACCESSOR_SETTER, *setter, attr);
4361 if (ok->IsFailure()) return ok;
4362 }
4363
4364 return isolate->heap()->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00004365}
4366
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004367// Implements part of 8.12.9 DefineOwnProperty.
4368// There are 3 cases that lead here:
4369// Step 4a - define a new data property.
4370// Steps 9b & 12 - replace an existing accessor property with a data property.
4371// Step 12 - update an existing data property with a data or generic
4372// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004373RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004374 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004375 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004376 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4377 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004378 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004379 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00004380 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004381 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4382
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004383 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004384 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004385
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004386 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004387 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004388 Object* callback = result.GetCallbackObject();
4389 // To be compatible with Safari we do not change the value on API objects
4390 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4391 // the value.
4392 if (callback->IsAccessorInfo()) {
4393 return isolate->heap()->undefined_value();
4394 }
4395 // Avoid redefining foreign callback as data property, just use the stored
4396 // setter to update the value instead.
4397 // TODO(mstarzinger): So far this only works if property attributes don't
4398 // change, this should be fixed once we cleanup the underlying code.
4399 if (callback->IsForeign() && result.GetAttributes() == attr) {
4400 return js_object->SetPropertyWithCallback(callback,
4401 *name,
4402 *obj_value,
4403 result.holder(),
4404 kStrictMode);
4405 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004406 }
4407
ager@chromium.org5c838252010-02-19 08:53:10 +00004408 // Take special care when attributes are different and there is already
4409 // a property. For simplicity we normalize the property which enables us
4410 // to not worry about changing the instance_descriptor and creating a new
4411 // map. The current version of SetObjectProperty does not handle attributes
4412 // correctly in the case where a property is a field and is reset with
4413 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004414 if (result.IsProperty() &&
4415 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004416 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004417 if (js_object->IsJSGlobalProxy()) {
4418 // Since the result is a property, the prototype will exist so
4419 // we don't have to check for null.
4420 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004421 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004422 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004423 // Use IgnoreAttributes version since a readonly property may be
4424 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004425 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4426 *obj_value,
4427 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004428 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430 return Runtime::ForceSetObjectProperty(isolate,
4431 js_object,
4432 name,
4433 obj_value,
4434 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004435}
4436
4437
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004438MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4439 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004440 Handle<Object> key,
4441 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004442 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004443 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004444 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004445 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004446
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004448 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004449 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004450 isolate->factory()->NewTypeError("non_object_property_store",
4451 HandleVector(args, 2));
4452 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004453 }
4454
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004455 if (object->IsJSProxy()) {
4456 bool has_pending_exception = false;
4457 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4458 if (has_pending_exception) return Failure::Exception();
4459 return JSProxy::cast(*object)->SetProperty(
4460 String::cast(*name), *value, attr, strict_mode);
4461 }
4462
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004463 // If the object isn't a JavaScript object, we ignore the store.
4464 if (!object->IsJSObject()) return *value;
4465
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004466 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4467
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004468 // Check if the given key is an array index.
4469 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004470 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4472 // of a string using [] notation. We need to support this too in
4473 // JavaScript.
4474 // In the case of a String object we just need to redirect the assignment to
4475 // the underlying string if the index is in range. Since the underlying
4476 // string does nothing with the assignment then we can ignore such
4477 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004478 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004479 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004480 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004482 Handle<Object> result = JSObject::SetElement(
4483 js_object, index, value, attr, strict_mode, set_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004484 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 return *value;
4486 }
4487
4488 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004489 Handle<Object> result;
4490 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004491 result = JSObject::SetElement(
4492 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004494 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004495 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004496 result = JSReceiver::SetProperty(
4497 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004499 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004500 return *value;
4501 }
4502
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004504 bool has_pending_exception = false;
4505 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4506 if (has_pending_exception) return Failure::Exception();
4507 Handle<String> name = Handle<String>::cast(converted);
4508
4509 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004510 return js_object->SetElement(
4511 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004512 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004513 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004514 }
4515}
4516
4517
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004518MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4519 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004520 Handle<Object> key,
4521 Handle<Object> value,
4522 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004523 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004524
4525 // Check if the given key is an array index.
4526 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004527 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004528 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4529 // of a string using [] notation. We need to support this too in
4530 // JavaScript.
4531 // In the case of a String object we just need to redirect the assignment to
4532 // the underlying string if the index is in range. Since the underlying
4533 // string does nothing with the assignment then we can ignore such
4534 // assignments.
4535 if (js_object->IsStringObjectWithCharacterAt(index)) {
4536 return *value;
4537 }
4538
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004539 return js_object->SetElement(
4540 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004541 }
4542
4543 if (key->IsString()) {
4544 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004545 return js_object->SetElement(
4546 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004547 } else {
4548 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004549 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004550 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4551 *value,
4552 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004553 }
4554 }
4555
4556 // Call-back into JavaScript to convert the key to a string.
4557 bool has_pending_exception = false;
4558 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4559 if (has_pending_exception) return Failure::Exception();
4560 Handle<String> name = Handle<String>::cast(converted);
4561
4562 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004563 return js_object->SetElement(
4564 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004565 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004566 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004567 }
4568}
4569
4570
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004571MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004572 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004573 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004574 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004575
4576 // Check if the given key is an array index.
4577 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004578 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004579 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4580 // characters of a string using [] notation. In the case of a
4581 // String object we just need to redirect the deletion to the
4582 // underlying string if the index is in range. Since the
4583 // underlying string does nothing with the deletion, we can ignore
4584 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004585 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004586 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004587 }
4588
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004589 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004590 }
4591
4592 Handle<String> key_string;
4593 if (key->IsString()) {
4594 key_string = Handle<String>::cast(key);
4595 } else {
4596 // Call-back into JavaScript to convert the key to a string.
4597 bool has_pending_exception = false;
4598 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4599 if (has_pending_exception) return Failure::Exception();
4600 key_string = Handle<String>::cast(converted);
4601 }
4602
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004603 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004604 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004605}
4606
4607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004608RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004609 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004610 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004611
4612 Handle<Object> object = args.at<Object>(0);
4613 Handle<Object> key = args.at<Object>(1);
4614 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004615 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004616 RUNTIME_ASSERT(
4617 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004618 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004619 PropertyAttributes attributes =
4620 static_cast<PropertyAttributes>(unchecked_attributes);
4621
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004622 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004623 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004624 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004625 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004626 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004627
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004628 return Runtime::SetObjectProperty(isolate,
4629 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004630 key,
4631 value,
4632 attributes,
4633 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634}
4635
4636
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004637RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4638 NoHandleAllocation ha;
4639 RUNTIME_ASSERT(args.length() == 1);
4640 Handle<Object> object = args.at<Object>(0);
4641 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4642}
4643
4644
4645RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4646 NoHandleAllocation ha;
4647 RUNTIME_ASSERT(args.length() == 1);
4648 Handle<Object> object = args.at<Object>(0);
4649 return TransitionElements(object, FAST_ELEMENTS, isolate);
4650}
4651
4652
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004653// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004654// This is used to decide if we should transform null and undefined
4655// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004656RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004657 NoHandleAllocation ha;
4658 RUNTIME_ASSERT(args.length() == 1);
4659
4660 Handle<Object> object = args.at<Object>(0);
4661
4662 if (object->IsJSFunction()) {
4663 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004664 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004665 }
4666 return isolate->heap()->undefined_value();
4667}
4668
4669
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004670RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4671 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004672 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004673 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4674 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004675 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004676 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4677 HandleScope scope;
4678
4679 Object* raw_boilerplate_object = literals->get(literal_index);
4680 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4681#if DEBUG
4682 ElementsKind elements_kind = object->GetElementsKind();
4683#endif
4684 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4685 // Smis should never trigger transitions.
4686 ASSERT(!value->IsSmi());
4687
4688 if (value->IsNumber()) {
4689 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004690 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4691 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004692 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4693 FixedDoubleArray* double_array =
4694 FixedDoubleArray::cast(object->elements());
4695 HeapNumber* number = HeapNumber::cast(*value);
4696 double_array->set(store_index, number->Number());
4697 } else {
4698 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4699 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004700 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4701 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004702 FixedArray* object_array =
4703 FixedArray::cast(object->elements());
4704 object_array->set(store_index, *value);
4705 }
4706 return *object;
4707}
4708
4709
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710// Set a local property, even if it is READ_ONLY. If the property does not
4711// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004712RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004713 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004714 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004715 CONVERT_ARG_CHECKED(JSObject, object, 0);
4716 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004717 // Compute attributes.
4718 PropertyAttributes attributes = NONE;
4719 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004720 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004721 // Only attribute bits should be set.
4722 RUNTIME_ASSERT(
4723 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4724 attributes = static_cast<PropertyAttributes>(unchecked_value);
4725 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004726
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004727 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004728 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004729}
4730
4731
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004732RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004733 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004734 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004735
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004736 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4737 CONVERT_ARG_CHECKED(String, key, 1);
4738 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004739 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004740 ? JSReceiver::STRICT_DELETION
4741 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742}
4743
4744
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004745static Object* HasLocalPropertyImplementation(Isolate* isolate,
4746 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004747 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004748 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004749 // Handle hidden prototypes. If there's a hidden prototype above this thing
4750 // then we have to check it for properties, because they are supposed to
4751 // look like they are on this object.
4752 Handle<Object> proto(object->GetPrototype());
4753 if (proto->IsJSObject() &&
4754 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 return HasLocalPropertyImplementation(isolate,
4756 Handle<JSObject>::cast(proto),
4757 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004758 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004759 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004760}
4761
4762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004763RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 NoHandleAllocation ha;
4765 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004766 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004767
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004768 uint32_t index;
4769 const bool key_is_array_index = key->AsArrayIndex(&index);
4770
ager@chromium.org9085a012009-05-11 19:22:57 +00004771 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004772 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004773 if (obj->IsJSObject()) {
4774 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004775 // Fast case: either the key is a real named property or it is not
4776 // an array index and there are no interceptors or hidden
4777 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004779 Map* map = object->map();
4780 if (!key_is_array_index &&
4781 !map->has_named_interceptor() &&
4782 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4783 return isolate->heap()->false_value();
4784 }
4785 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004786 HandleScope scope(isolate);
4787 return HasLocalPropertyImplementation(isolate,
4788 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004789 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004790 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004791 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004792 String* string = String::cast(obj);
4793 if (index < static_cast<uint32_t>(string->length())) {
4794 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795 }
4796 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004797 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798}
4799
4800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004801RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004802 NoHandleAllocation na;
4803 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004804 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4805 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004807 bool result = receiver->HasProperty(key);
4808 if (isolate->has_pending_exception()) return Failure::Exception();
4809 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004810}
4811
4812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004813RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814 NoHandleAllocation na;
4815 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004816 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4817 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004818
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004819 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004820 if (isolate->has_pending_exception()) return Failure::Exception();
4821 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822}
4823
4824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004825RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 NoHandleAllocation ha;
4827 ASSERT(args.length() == 2);
4828
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004829 CONVERT_ARG_CHECKED(JSObject, object, 0);
4830 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831
4832 uint32_t index;
4833 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004834 JSObject::LocalElementType type = object->HasLocalElement(index);
4835 switch (type) {
4836 case JSObject::UNDEFINED_ELEMENT:
4837 case JSObject::STRING_CHARACTER_ELEMENT:
4838 return isolate->heap()->false_value();
4839 case JSObject::INTERCEPTED_ELEMENT:
4840 case JSObject::FAST_ELEMENT:
4841 return isolate->heap()->true_value();
4842 case JSObject::DICTIONARY_ELEMENT: {
4843 if (object->IsJSGlobalProxy()) {
4844 Object* proto = object->GetPrototype();
4845 if (proto->IsNull()) {
4846 return isolate->heap()->false_value();
4847 }
4848 ASSERT(proto->IsJSGlobalObject());
4849 object = JSObject::cast(proto);
4850 }
4851 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004852 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004853 if (elements->map() ==
4854 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004855 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004856 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004857 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004858 }
4859 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004860 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004861 PropertyDetails details = dictionary->DetailsAt(entry);
4862 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4863 }
4864 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865 }
4866
ager@chromium.org870a0b62008-11-04 11:43:05 +00004867 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004868 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004869}
4870
4871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004872RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004873 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004874 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004875 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004876 bool threw = false;
4877 Handle<JSArray> result = GetKeysFor(object, &threw);
4878 if (threw) return Failure::Exception();
4879 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004880}
4881
4882
4883// Returns either a FixedArray as Runtime_GetPropertyNames,
4884// or, if the given object has an enum cache that contains
4885// all enumerable properties of the object and its prototypes
4886// have none, the map of the object. This is used to speed up
4887// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004888RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004889 ASSERT(args.length() == 1);
4890
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004891 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004892
4893 if (raw_object->IsSimpleEnum()) return raw_object->map();
4894
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004895 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004896 Handle<JSReceiver> object(raw_object);
4897 bool threw = false;
4898 Handle<FixedArray> content =
4899 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4900 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004901
4902 // Test again, since cache may have been built by preceding call.
4903 if (object->IsSimpleEnum()) return object->map();
4904
4905 return *content;
4906}
4907
4908
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004909// Find the length of the prototype chain that is to to handled as one. If a
4910// prototype object is hidden it is to be viewed as part of the the object it
4911// is prototype for.
4912static int LocalPrototypeChainLength(JSObject* obj) {
4913 int count = 1;
4914 Object* proto = obj->GetPrototype();
4915 while (proto->IsJSObject() &&
4916 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4917 count++;
4918 proto = JSObject::cast(proto)->GetPrototype();
4919 }
4920 return count;
4921}
4922
4923
4924// Return the names of the local named properties.
4925// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004926RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004927 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004928 ASSERT(args.length() == 1);
4929 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004930 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004931 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004932 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004933
4934 // Skip the global proxy as it has no properties and always delegates to the
4935 // real global object.
4936 if (obj->IsJSGlobalProxy()) {
4937 // Only collect names if access is permitted.
4938 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004939 !isolate->MayNamedAccess(*obj,
4940 isolate->heap()->undefined_value(),
4941 v8::ACCESS_KEYS)) {
4942 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4943 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004944 }
4945 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4946 }
4947
4948 // Find the number of objects making up this.
4949 int length = LocalPrototypeChainLength(*obj);
4950
4951 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004952 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004953 int total_property_count = 0;
4954 Handle<JSObject> jsproto = obj;
4955 for (int i = 0; i < length; i++) {
4956 // Only collect names if access is permitted.
4957 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004958 !isolate->MayNamedAccess(*jsproto,
4959 isolate->heap()->undefined_value(),
4960 v8::ACCESS_KEYS)) {
4961 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4962 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004963 }
4964 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004965 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004966 local_property_count[i] = n;
4967 total_property_count += n;
4968 if (i < length - 1) {
4969 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4970 }
4971 }
4972
4973 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004974 Handle<FixedArray> names =
4975 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004976
4977 // Get the property names.
4978 jsproto = obj;
4979 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004980 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004981 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004982 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4983 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004984 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004985 proto_with_hidden_properties++;
4986 }
4987 if (i < length - 1) {
4988 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4989 }
4990 }
4991
4992 // Filter out name of hidden propeties object.
4993 if (proto_with_hidden_properties > 0) {
4994 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004995 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004996 names->length() - proto_with_hidden_properties);
4997 int dest_pos = 0;
4998 for (int i = 0; i < total_property_count; i++) {
4999 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005000 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005001 continue;
5002 }
5003 names->set(dest_pos++, name);
5004 }
5005 }
5006
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005007 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005008}
5009
5010
5011// Return the names of the local indexed properties.
5012// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005013RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005014 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005015 ASSERT(args.length() == 1);
5016 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005017 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005018 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005019 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005020
5021 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005022 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005023 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005024 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005025}
5026
5027
5028// Return information on whether an object has a named or indexed interceptor.
5029// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005030RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005031 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005032 ASSERT(args.length() == 1);
5033 if (!args[0]->IsJSObject()) {
5034 return Smi::FromInt(0);
5035 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005036 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005037
5038 int result = 0;
5039 if (obj->HasNamedInterceptor()) result |= 2;
5040 if (obj->HasIndexedInterceptor()) result |= 1;
5041
5042 return Smi::FromInt(result);
5043}
5044
5045
5046// Return property names from named interceptor.
5047// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005048RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005049 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005050 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005051 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005052
5053 if (obj->HasNamedInterceptor()) {
5054 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5055 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5056 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005057 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005058}
5059
5060
5061// Return element names from indexed interceptor.
5062// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005063RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005064 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005065 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005066 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005067
5068 if (obj->HasIndexedInterceptor()) {
5069 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5070 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5071 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005073}
5074
5075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005076RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005077 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005078 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005080 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005081
5082 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005083 // Do access checks before going to the global object.
5084 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005085 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005086 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5088 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005089 }
5090
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005091 Handle<Object> proto(object->GetPrototype());
5092 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005093 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005094 object = Handle<JSObject>::cast(proto);
5095 }
5096
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005097 bool threw = false;
5098 Handle<FixedArray> contents =
5099 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5100 if (threw) return Failure::Exception();
5101
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005102 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5103 // property array and since the result is mutable we have to create
5104 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005105 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005106 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005107 for (int i = 0; i < length; i++) {
5108 Object* entry = contents->get(i);
5109 if (entry->IsString()) {
5110 copy->set(i, entry);
5111 } else {
5112 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005113 HandleScope scope(isolate);
5114 Handle<Object> entry_handle(entry, isolate);
5115 Handle<Object> entry_str =
5116 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005117 copy->set(i, *entry_str);
5118 }
5119 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005120 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005121}
5122
5123
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005124RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005125 NoHandleAllocation ha;
5126 ASSERT(args.length() == 1);
5127
5128 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005129 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005130 it.AdvanceToArgumentsFrame();
5131 JavaScriptFrame* frame = it.frame();
5132
5133 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005134 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005135
5136 // Try to convert the key to an index. If successful and within
5137 // index return the the argument from the frame.
5138 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005139 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005140 return frame->GetParameter(index);
5141 }
5142
5143 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005144 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005145 bool exception = false;
5146 Handle<Object> converted =
5147 Execution::ToString(args.at<Object>(0), &exception);
5148 if (exception) return Failure::Exception();
5149 Handle<String> key = Handle<String>::cast(converted);
5150
5151 // Try to convert the string key into an array index.
5152 if (key->AsArrayIndex(&index)) {
5153 if (index < n) {
5154 return frame->GetParameter(index);
5155 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005156 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005157 }
5158 }
5159
5160 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005161 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5162 if (key->Equals(isolate->heap()->callee_symbol())) {
5163 Object* function = frame->function();
5164 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005165 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005166 return isolate->Throw(*isolate->factory()->NewTypeError(
5167 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5168 }
5169 return function;
5170 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005171
5172 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005173 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005174}
5175
5176
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005177RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005178 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005179 Object* object = args[0];
5180 return (object->IsJSObject() && !object->IsGlobalObject())
5181 ? JSObject::cast(object)->TransformToFastProperties(0)
5182 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005183}
5184
5185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005186RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005187 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005188 Object* obj = args[0];
5189 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5190 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5191 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005192}
5193
5194
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005195RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196 NoHandleAllocation ha;
5197 ASSERT(args.length() == 1);
5198
5199 return args[0]->ToBoolean();
5200}
5201
5202
5203// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5204// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005205RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 NoHandleAllocation ha;
5207
5208 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005209 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005210 HeapObject* heap_obj = HeapObject::cast(obj);
5211
5212 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005213 if (heap_obj->map()->is_undetectable()) {
5214 return isolate->heap()->undefined_symbol();
5215 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216
5217 InstanceType instance_type = heap_obj->map()->instance_type();
5218 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005219 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005220 }
5221
5222 switch (instance_type) {
5223 case ODDBALL_TYPE:
5224 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005225 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226 }
5227 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005228 return FLAG_harmony_typeof
5229 ? isolate->heap()->null_symbol()
5230 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005231 }
5232 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005233 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005234 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005235 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005236 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005237 default:
5238 // For any kind of object not handled above, the spec rule for
5239 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005240 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005241 }
5242}
5243
5244
lrn@chromium.org25156de2010-04-06 13:10:27 +00005245static bool AreDigits(const char*s, int from, int to) {
5246 for (int i = from; i < to; i++) {
5247 if (s[i] < '0' || s[i] > '9') return false;
5248 }
5249
5250 return true;
5251}
5252
5253
5254static int ParseDecimalInteger(const char*s, int from, int to) {
5255 ASSERT(to - from < 10); // Overflow is not possible.
5256 ASSERT(from < to);
5257 int d = s[from] - '0';
5258
5259 for (int i = from + 1; i < to; i++) {
5260 d = 10 * d + (s[i] - '0');
5261 }
5262
5263 return d;
5264}
5265
5266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005267RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005268 NoHandleAllocation ha;
5269 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005270 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005271 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005272
5273 // Fast case: short integer or some sorts of junk values.
5274 int len = subject->length();
5275 if (subject->IsSeqAsciiString()) {
5276 if (len == 0) return Smi::FromInt(0);
5277
5278 char const* data = SeqAsciiString::cast(subject)->GetChars();
5279 bool minus = (data[0] == '-');
5280 int start_pos = (minus ? 1 : 0);
5281
5282 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005283 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005284 } else if (data[start_pos] > '9') {
5285 // Fast check for a junk value. A valid string may start from a
5286 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5287 // the 'I' character ('Infinity'). All of that have codes not greater than
5288 // '9' except 'I'.
5289 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005290 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005291 }
5292 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5293 // The maximal/minimal smi has 10 digits. If the string has less digits we
5294 // know it will fit into the smi-data type.
5295 int d = ParseDecimalInteger(data, start_pos, len);
5296 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005297 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005298 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005299 } else if (!subject->HasHashCode() &&
5300 len <= String::kMaxArrayIndexSize &&
5301 (len == 1 || data[0] != '0')) {
5302 // String hash is not calculated yet but all the data are present.
5303 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005304 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005305#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005306 subject->Hash(); // Force hash calculation.
5307 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5308 static_cast<int>(hash));
5309#endif
5310 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005311 }
5312 return Smi::FromInt(d);
5313 }
5314 }
5315
5316 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005317 return isolate->heap()->NumberFromDouble(
5318 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319}
5320
5321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005322RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005323 NoHandleAllocation ha;
5324 ASSERT(args.length() == 1);
5325
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005326 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005327 int length = Smi::cast(codes->length())->value();
5328
5329 // Check if the string can be ASCII.
5330 int i;
5331 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005332 Object* element;
5333 { MaybeObject* maybe_element = codes->GetElement(i);
5334 // We probably can't get an exception here, but just in order to enforce
5335 // the checking of inputs in the runtime calls we check here.
5336 if (!maybe_element->ToObject(&element)) return maybe_element;
5337 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005338 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5339 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5340 break;
5341 }
5342
lrn@chromium.org303ada72010-10-27 09:33:13 +00005343 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005344 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005345 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005346 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005347 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005348 }
5349
lrn@chromium.org303ada72010-10-27 09:33:13 +00005350 Object* object = NULL;
5351 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005352 String* result = String::cast(object);
5353 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005354 Object* element;
5355 { MaybeObject* maybe_element = codes->GetElement(i);
5356 if (!maybe_element->ToObject(&element)) return maybe_element;
5357 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005358 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005359 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005360 }
5361 return result;
5362}
5363
5364
5365// kNotEscaped is generated by the following:
5366//
5367// #!/bin/perl
5368// for (my $i = 0; $i < 256; $i++) {
5369// print "\n" if $i % 16 == 0;
5370// my $c = chr($i);
5371// my $escaped = 1;
5372// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5373// print $escaped ? "0, " : "1, ";
5374// }
5375
5376
5377static bool IsNotEscaped(uint16_t character) {
5378 // Only for 8 bit characters, the rest are always escaped (in a different way)
5379 ASSERT(character < 256);
5380 static const char kNotEscaped[256] = {
5381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5384 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5385 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5386 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5387 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5388 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5389 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5390 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5391 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5392 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5393 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5394 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5395 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5396 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5397 };
5398 return kNotEscaped[character] != 0;
5399}
5400
5401
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005402RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005403 const char hex_chars[] = "0123456789ABCDEF";
5404 NoHandleAllocation ha;
5405 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005406 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005407
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005408 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409
5410 int escaped_length = 0;
5411 int length = source->length();
5412 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005413 Access<StringInputBuffer> buffer(
5414 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005415 buffer->Reset(source);
5416 while (buffer->has_more()) {
5417 uint16_t character = buffer->GetNext();
5418 if (character >= 256) {
5419 escaped_length += 6;
5420 } else if (IsNotEscaped(character)) {
5421 escaped_length++;
5422 } else {
5423 escaped_length += 3;
5424 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005425 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005426 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005427 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005428 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005429 return Failure::OutOfMemoryException();
5430 }
5431 }
5432 }
5433 // No length change implies no change. Return original string if no change.
5434 if (escaped_length == length) {
5435 return source;
5436 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005437 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005438 { MaybeObject* maybe_o =
5439 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005440 if (!maybe_o->ToObject(&o)) return maybe_o;
5441 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005442 String* destination = String::cast(o);
5443 int dest_position = 0;
5444
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005445 Access<StringInputBuffer> buffer(
5446 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005447 buffer->Rewind();
5448 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005449 uint16_t chr = buffer->GetNext();
5450 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005451 destination->Set(dest_position, '%');
5452 destination->Set(dest_position+1, 'u');
5453 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5454 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5455 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5456 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005457 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005458 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005459 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005460 dest_position++;
5461 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005462 destination->Set(dest_position, '%');
5463 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5464 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465 dest_position += 3;
5466 }
5467 }
5468 return destination;
5469}
5470
5471
5472static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5473 static const signed char kHexValue['g'] = {
5474 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5475 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5476 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5477 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5478 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5479 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5480 -1, 10, 11, 12, 13, 14, 15 };
5481
5482 if (character1 > 'f') return -1;
5483 int hi = kHexValue[character1];
5484 if (hi == -1) return -1;
5485 if (character2 > 'f') return -1;
5486 int lo = kHexValue[character2];
5487 if (lo == -1) return -1;
5488 return (hi << 4) + lo;
5489}
5490
5491
ager@chromium.org870a0b62008-11-04 11:43:05 +00005492static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005493 int i,
5494 int length,
5495 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005496 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005497 int32_t hi = 0;
5498 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005499 if (character == '%' &&
5500 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005501 source->Get(i + 1) == 'u' &&
5502 (hi = TwoDigitHex(source->Get(i + 2),
5503 source->Get(i + 3))) != -1 &&
5504 (lo = TwoDigitHex(source->Get(i + 4),
5505 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005506 *step = 6;
5507 return (hi << 8) + lo;
5508 } else if (character == '%' &&
5509 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005510 (lo = TwoDigitHex(source->Get(i + 1),
5511 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005512 *step = 3;
5513 return lo;
5514 } else {
5515 *step = 1;
5516 return character;
5517 }
5518}
5519
5520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005521RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005522 NoHandleAllocation ha;
5523 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005524 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005525
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005526 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005527
5528 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005529 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005530
5531 int unescaped_length = 0;
5532 for (int i = 0; i < length; unescaped_length++) {
5533 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005534 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005535 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005536 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005537 i += step;
5538 }
5539
5540 // No length change implies no change. Return original string if no change.
5541 if (unescaped_length == length)
5542 return source;
5543
lrn@chromium.org303ada72010-10-27 09:33:13 +00005544 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005545 { MaybeObject* maybe_o =
5546 ascii ?
5547 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5548 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005549 if (!maybe_o->ToObject(&o)) return maybe_o;
5550 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005551 String* destination = String::cast(o);
5552
5553 int dest_position = 0;
5554 for (int i = 0; i < length; dest_position++) {
5555 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005556 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005557 i += step;
5558 }
5559 return destination;
5560}
5561
5562
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005563static const unsigned int kQuoteTableLength = 128u;
5564
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005565static const int kJsonQuotesCharactersPerEntry = 8;
5566static const char* const JsonQuotes =
5567 "\\u0000 \\u0001 \\u0002 \\u0003 "
5568 "\\u0004 \\u0005 \\u0006 \\u0007 "
5569 "\\b \\t \\n \\u000b "
5570 "\\f \\r \\u000e \\u000f "
5571 "\\u0010 \\u0011 \\u0012 \\u0013 "
5572 "\\u0014 \\u0015 \\u0016 \\u0017 "
5573 "\\u0018 \\u0019 \\u001a \\u001b "
5574 "\\u001c \\u001d \\u001e \\u001f "
5575 " ! \\\" # "
5576 "$ % & ' "
5577 "( ) * + "
5578 ", - . / "
5579 "0 1 2 3 "
5580 "4 5 6 7 "
5581 "8 9 : ; "
5582 "< = > ? "
5583 "@ A B C "
5584 "D E F G "
5585 "H I J K "
5586 "L M N O "
5587 "P Q R S "
5588 "T U V W "
5589 "X Y Z [ "
5590 "\\\\ ] ^ _ "
5591 "` a b c "
5592 "d e f g "
5593 "h i j k "
5594 "l m n o "
5595 "p q r s "
5596 "t u v w "
5597 "x y z { "
5598 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005599
5600
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005601// For a string that is less than 32k characters it should always be
5602// possible to allocate it in new space.
5603static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5604
5605
5606// Doing JSON quoting cannot make the string more than this many times larger.
5607static const int kJsonQuoteWorstCaseBlowup = 6;
5608
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005609static const int kSpaceForQuotesAndComma = 3;
5610static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005611
5612// Covers the entire ASCII range (all other characters are unchanged by JSON
5613// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005614static const byte JsonQuoteLengths[kQuoteTableLength] = {
5615 6, 6, 6, 6, 6, 6, 6, 6,
5616 2, 2, 2, 6, 2, 2, 6, 6,
5617 6, 6, 6, 6, 6, 6, 6, 6,
5618 6, 6, 6, 6, 6, 6, 6, 6,
5619 1, 1, 2, 1, 1, 1, 1, 1,
5620 1, 1, 1, 1, 1, 1, 1, 1,
5621 1, 1, 1, 1, 1, 1, 1, 1,
5622 1, 1, 1, 1, 1, 1, 1, 1,
5623 1, 1, 1, 1, 1, 1, 1, 1,
5624 1, 1, 1, 1, 1, 1, 1, 1,
5625 1, 1, 1, 1, 1, 1, 1, 1,
5626 1, 1, 1, 1, 2, 1, 1, 1,
5627 1, 1, 1, 1, 1, 1, 1, 1,
5628 1, 1, 1, 1, 1, 1, 1, 1,
5629 1, 1, 1, 1, 1, 1, 1, 1,
5630 1, 1, 1, 1, 1, 1, 1, 1,
5631};
5632
5633
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005634template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005635MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005636
5637
5638template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005639MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5640 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005641}
5642
5643
5644template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005645MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5646 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005647}
5648
5649
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005650template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005651static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5652 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005653 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005654 const Char* read_cursor = characters.start();
5655 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005656 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005657 int quoted_length = kSpaceForQuotes;
5658 while (read_cursor < end) {
5659 Char c = *(read_cursor++);
5660 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5661 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005662 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005663 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005664 }
5665 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005666 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5667 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005668 Object* new_object;
5669 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005670 return new_alloc;
5671 }
5672 StringType* new_string = StringType::cast(new_object);
5673
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005674 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005675 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005676 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005677 *(write_cursor++) = '"';
5678
5679 read_cursor = characters.start();
5680 while (read_cursor < end) {
5681 Char c = *(read_cursor++);
5682 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5683 *(write_cursor++) = c;
5684 } else {
5685 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5686 const char* replacement = JsonQuotes +
5687 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5688 for (int i = 0; i < len; i++) {
5689 *write_cursor++ = *replacement++;
5690 }
5691 }
5692 }
5693 *(write_cursor++) = '"';
5694 return new_string;
5695}
5696
5697
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005698template <typename SinkChar, typename SourceChar>
5699static inline SinkChar* WriteQuoteJsonString(
5700 Isolate* isolate,
5701 SinkChar* write_cursor,
5702 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005703 // SinkChar is only char if SourceChar is guaranteed to be char.
5704 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005705 const SourceChar* read_cursor = characters.start();
5706 const SourceChar* end = read_cursor + characters.length();
5707 *(write_cursor++) = '"';
5708 while (read_cursor < end) {
5709 SourceChar c = *(read_cursor++);
5710 if (sizeof(SourceChar) > 1u &&
5711 static_cast<unsigned>(c) >= kQuoteTableLength) {
5712 *(write_cursor++) = static_cast<SinkChar>(c);
5713 } else {
5714 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5715 const char* replacement = JsonQuotes +
5716 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5717 write_cursor[0] = replacement[0];
5718 if (len > 1) {
5719 write_cursor[1] = replacement[1];
5720 if (len > 2) {
5721 ASSERT(len == 6);
5722 write_cursor[2] = replacement[2];
5723 write_cursor[3] = replacement[3];
5724 write_cursor[4] = replacement[4];
5725 write_cursor[5] = replacement[5];
5726 }
5727 }
5728 write_cursor += len;
5729 }
5730 }
5731 *(write_cursor++) = '"';
5732 return write_cursor;
5733}
5734
5735
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005736template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005737static MaybeObject* QuoteJsonString(Isolate* isolate,
5738 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005739 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005740 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005741 int worst_case_length =
5742 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005743 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005744 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005745 }
5746
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005747 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5748 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005749 Object* new_object;
5750 if (!new_alloc->ToObject(&new_object)) {
5751 return new_alloc;
5752 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005753 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005754 // Even if our string is small enough to fit in new space we still have to
5755 // handle it being allocated in old space as may happen in the third
5756 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5757 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005758 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005759 }
5760 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005761 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005762
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005763 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005764 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005765 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005766 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5767 write_cursor,
5768 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005769 int final_length = static_cast<int>(
5770 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005771 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005772 isolate->heap()->new_space()->
5773 template ShrinkStringAtAllocationBoundary<StringType>(
5774 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005775 return new_string;
5776}
5777
5778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005779RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005780 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005781 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005782 if (!str->IsFlat()) {
5783 MaybeObject* try_flatten = str->TryFlatten();
5784 Object* flat;
5785 if (!try_flatten->ToObject(&flat)) {
5786 return try_flatten;
5787 }
5788 str = String::cast(flat);
5789 ASSERT(str->IsFlat());
5790 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005791 String::FlatContent flat = str->GetFlatContent();
5792 ASSERT(flat.IsFlat());
5793 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005794 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005795 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005796 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005797 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005798 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005799 }
5800}
5801
5802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005803RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005804 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005805 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005806 if (!str->IsFlat()) {
5807 MaybeObject* try_flatten = str->TryFlatten();
5808 Object* flat;
5809 if (!try_flatten->ToObject(&flat)) {
5810 return try_flatten;
5811 }
5812 str = String::cast(flat);
5813 ASSERT(str->IsFlat());
5814 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005815 String::FlatContent flat = str->GetFlatContent();
5816 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005817 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005818 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005819 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005820 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005821 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005822 }
5823}
5824
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005825
5826template <typename Char, typename StringType>
5827static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5828 FixedArray* array,
5829 int worst_case_length) {
5830 int length = array->length();
5831
5832 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5833 worst_case_length);
5834 Object* new_object;
5835 if (!new_alloc->ToObject(&new_object)) {
5836 return new_alloc;
5837 }
5838 if (!isolate->heap()->new_space()->Contains(new_object)) {
5839 // Even if our string is small enough to fit in new space we still have to
5840 // handle it being allocated in old space as may happen in the third
5841 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5842 // CEntryStub::GenerateCore.
5843 return isolate->heap()->undefined_value();
5844 }
5845 AssertNoAllocation no_gc;
5846 StringType* new_string = StringType::cast(new_object);
5847 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5848
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005849 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005850 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005851 *(write_cursor++) = '[';
5852 for (int i = 0; i < length; i++) {
5853 if (i != 0) *(write_cursor++) = ',';
5854 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005855 String::FlatContent content = str->GetFlatContent();
5856 ASSERT(content.IsFlat());
5857 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005858 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5859 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005860 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005861 } else {
5862 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5863 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005864 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005865 }
5866 }
5867 *(write_cursor++) = ']';
5868
5869 int final_length = static_cast<int>(
5870 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005871 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005872 isolate->heap()->new_space()->
5873 template ShrinkStringAtAllocationBoundary<StringType>(
5874 new_string, final_length);
5875 return new_string;
5876}
5877
5878
5879RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5880 NoHandleAllocation ha;
5881 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005882 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005883
5884 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5885 FixedArray* elements = FixedArray::cast(array->elements());
5886 int n = elements->length();
5887 bool ascii = true;
5888 int total_length = 0;
5889
5890 for (int i = 0; i < n; i++) {
5891 Object* elt = elements->get(i);
5892 if (!elt->IsString()) return isolate->heap()->undefined_value();
5893 String* element = String::cast(elt);
5894 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5895 total_length += element->length();
5896 if (ascii && element->IsTwoByteRepresentation()) {
5897 ascii = false;
5898 }
5899 }
5900
5901 int worst_case_length =
5902 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5903 + total_length * kJsonQuoteWorstCaseBlowup;
5904
5905 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5906 return isolate->heap()->undefined_value();
5907 }
5908
5909 if (ascii) {
5910 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5911 elements,
5912 worst_case_length);
5913 } else {
5914 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5915 elements,
5916 worst_case_length);
5917 }
5918}
5919
5920
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005921RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005922 NoHandleAllocation ha;
5923
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005924 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005925 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005926
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005927 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928
lrn@chromium.org25156de2010-04-06 13:10:27 +00005929 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005930 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005931 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005932}
5933
5934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005935RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005936 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005937 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005938
5939 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005940 double value = StringToDouble(isolate->unicode_cache(),
5941 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005942
5943 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005944 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005945}
5946
5947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005948template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005949MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005950 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005951 String* s,
5952 int length,
5953 int input_string_length,
5954 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005955 // We try this twice, once with the assumption that the result is no longer
5956 // than the input and, if that assumption breaks, again with the exact
5957 // length. This may not be pretty, but it is nicer than what was here before
5958 // and I hereby claim my vaffel-is.
5959 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005960 // Allocate the resulting string.
5961 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005962 // NOTE: This assumes that the upper/lower case of an ASCII
5963 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964 // might break in the future if we implement more context and locale
5965 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005966 Object* o;
5967 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005968 ? isolate->heap()->AllocateRawAsciiString(length)
5969 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005970 if (!maybe_o->ToObject(&o)) return maybe_o;
5971 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005972 String* result = String::cast(o);
5973 bool has_changed_character = false;
5974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005975 // Convert all characters to upper case, assuming that they will fit
5976 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005977 Access<StringInputBuffer> buffer(
5978 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005980 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 // We can assume that the string is not empty
5982 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005983 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005984 bool has_next = buffer->has_more();
5985 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986 int char_length = mapping->get(current, next, chars);
5987 if (char_length == 0) {
5988 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005989 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990 i++;
5991 } else if (char_length == 1) {
5992 // Common case: converting the letter resulted in one character.
5993 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005994 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995 has_changed_character = true;
5996 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005997 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 // We've assumed that the result would be as long as the
5999 // input but here is a character that converts to several
6000 // characters. No matter, we calculate the exact length
6001 // of the result and try the whole thing again.
6002 //
6003 // Note that this leaves room for optimization. We could just
6004 // memcpy what we already have to the result string. Also,
6005 // the result string is the last object allocated we could
6006 // "realloc" it and probably, in the vast majority of cases,
6007 // extend the existing string to be able to hold the full
6008 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006009 int next_length = 0;
6010 if (has_next) {
6011 next_length = mapping->get(next, 0, chars);
6012 if (next_length == 0) next_length = 1;
6013 }
6014 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015 while (buffer->has_more()) {
6016 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006017 // NOTE: we use 0 as the next character here because, while
6018 // the next character may affect what a character converts to,
6019 // it does not in any case affect the length of what it convert
6020 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006021 int char_length = mapping->get(current, 0, chars);
6022 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006023 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006024 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006025 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006026 return Failure::OutOfMemoryException();
6027 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006028 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006029 // Try again with the real length.
6030 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006031 } else {
6032 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006033 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006034 i++;
6035 }
6036 has_changed_character = true;
6037 }
6038 current = next;
6039 }
6040 if (has_changed_character) {
6041 return result;
6042 } else {
6043 // If we didn't actually change anything in doing the conversion
6044 // we simple return the result and let the converted string
6045 // become garbage; there is no reason to keep two identical strings
6046 // alive.
6047 return s;
6048 }
6049}
6050
6051
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006052namespace {
6053
lrn@chromium.org303ada72010-10-27 09:33:13 +00006054static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6055
6056
6057// Given a word and two range boundaries returns a word with high bit
6058// set in every byte iff the corresponding input byte was strictly in
6059// the range (m, n). All the other bits in the result are cleared.
6060// This function is only useful when it can be inlined and the
6061// boundaries are statically known.
6062// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006063// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006064static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006065 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006066 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6067 // Use strict inequalities since in edge cases the function could be
6068 // further simplified.
6069 ASSERT(0 < m && m < n && n < 0x7F);
6070 // Has high bit set in every w byte less than n.
6071 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6072 // Has high bit set in every w byte greater than m.
6073 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6074 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6075}
6076
6077
6078enum AsciiCaseConversion {
6079 ASCII_TO_LOWER,
6080 ASCII_TO_UPPER
6081};
6082
6083
6084template <AsciiCaseConversion dir>
6085struct FastAsciiConverter {
6086 static bool Convert(char* dst, char* src, int length) {
6087#ifdef DEBUG
6088 char* saved_dst = dst;
6089 char* saved_src = src;
6090#endif
6091 // We rely on the distance between upper and lower case letters
6092 // being a known power of 2.
6093 ASSERT('a' - 'A' == (1 << 5));
6094 // Boundaries for the range of input characters than require conversion.
6095 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6096 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6097 bool changed = false;
6098 char* const limit = src + length;
6099#ifdef V8_HOST_CAN_READ_UNALIGNED
6100 // Process the prefix of the input that requires no conversion one
6101 // (machine) word at a time.
6102 while (src <= limit - sizeof(uintptr_t)) {
6103 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6104 if (AsciiRangeMask(w, lo, hi) != 0) {
6105 changed = true;
6106 break;
6107 }
6108 *reinterpret_cast<uintptr_t*>(dst) = w;
6109 src += sizeof(uintptr_t);
6110 dst += sizeof(uintptr_t);
6111 }
6112 // Process the remainder of the input performing conversion when
6113 // required one word at a time.
6114 while (src <= limit - sizeof(uintptr_t)) {
6115 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6116 uintptr_t m = AsciiRangeMask(w, lo, hi);
6117 // The mask has high (7th) bit set in every byte that needs
6118 // conversion and we know that the distance between cases is
6119 // 1 << 5.
6120 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6121 src += sizeof(uintptr_t);
6122 dst += sizeof(uintptr_t);
6123 }
6124#endif
6125 // Process the last few bytes of the input (or the whole input if
6126 // unaligned access is not supported).
6127 while (src < limit) {
6128 char c = *src;
6129 if (lo < c && c < hi) {
6130 c ^= (1 << 5);
6131 changed = true;
6132 }
6133 *dst = c;
6134 ++src;
6135 ++dst;
6136 }
6137#ifdef DEBUG
6138 CheckConvert(saved_dst, saved_src, length, changed);
6139#endif
6140 return changed;
6141 }
6142
6143#ifdef DEBUG
6144 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6145 bool expected_changed = false;
6146 for (int i = 0; i < length; i++) {
6147 if (dst[i] == src[i]) continue;
6148 expected_changed = true;
6149 if (dir == ASCII_TO_LOWER) {
6150 ASSERT('A' <= src[i] && src[i] <= 'Z');
6151 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6152 } else {
6153 ASSERT(dir == ASCII_TO_UPPER);
6154 ASSERT('a' <= src[i] && src[i] <= 'z');
6155 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6156 }
6157 }
6158 ASSERT(expected_changed == changed);
6159 }
6160#endif
6161};
6162
6163
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006164struct ToLowerTraits {
6165 typedef unibrow::ToLowercase UnibrowConverter;
6166
lrn@chromium.org303ada72010-10-27 09:33:13 +00006167 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006168};
6169
6170
6171struct ToUpperTraits {
6172 typedef unibrow::ToUppercase UnibrowConverter;
6173
lrn@chromium.org303ada72010-10-27 09:33:13 +00006174 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006175};
6176
6177} // namespace
6178
6179
6180template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006181MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006182 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006183 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006184 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006185 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006186 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006187 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006188
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006189 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006190 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006191 if (length == 0) return s;
6192
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006193 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006194 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006195 // NOTE: This assumes that the upper/lower case of an ASCII
6196 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006197 // might break in the future if we implement more context and locale
6198 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006199 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006200 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006201 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006202 if (!maybe_o->ToObject(&o)) return maybe_o;
6203 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006204 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006205 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006206 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006207 return has_changed_character ? result : s;
6208 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006209
lrn@chromium.org303ada72010-10-27 09:33:13 +00006210 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006211 { MaybeObject* maybe_answer =
6212 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006213 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6214 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006215 if (answer->IsSmi()) {
6216 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006217 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006218 ConvertCaseHelper(isolate,
6219 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006220 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6221 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006222 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006223 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006224}
6225
6226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006227RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006228 return ConvertCase<ToLowerTraits>(
6229 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006230}
6231
6232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006233RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006234 return ConvertCase<ToUpperTraits>(
6235 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006236}
6237
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006238
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006239static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006240 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006241}
6242
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006243
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006244RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006245 NoHandleAllocation ha;
6246 ASSERT(args.length() == 3);
6247
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006248 CONVERT_ARG_CHECKED(String, s, 0);
6249 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6250 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006251
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006252 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006253 int length = s->length();
6254
6255 int left = 0;
6256 if (trimLeft) {
6257 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6258 left++;
6259 }
6260 }
6261
6262 int right = length;
6263 if (trimRight) {
6264 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6265 right--;
6266 }
6267 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006268 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006269}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006270
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006272RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006273 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006274 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006275 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6276 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006277 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6278
6279 int subject_length = subject->length();
6280 int pattern_length = pattern->length();
6281 RUNTIME_ASSERT(pattern_length > 0);
6282
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006283 if (limit == 0xffffffffu) {
6284 Handle<Object> cached_answer(StringSplitCache::Lookup(
6285 isolate->heap()->string_split_cache(),
6286 *subject,
6287 *pattern));
6288 if (*cached_answer != Smi::FromInt(0)) {
6289 Handle<JSArray> result =
6290 isolate->factory()->NewJSArrayWithElements(
6291 Handle<FixedArray>::cast(cached_answer));
6292 return *result;
6293 }
6294 }
6295
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006296 // The limit can be very large (0xffffffffu), but since the pattern
6297 // isn't empty, we can never create more parts than ~half the length
6298 // of the subject.
6299
6300 if (!subject->IsFlat()) FlattenString(subject);
6301
6302 static const int kMaxInitialListCapacity = 16;
6303
danno@chromium.org40cb8782011-05-25 07:58:50 +00006304 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305
6306 // Find (up to limit) indices of separator and end-of-string in subject
6307 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6308 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006309 if (!pattern->IsFlat()) FlattenString(pattern);
6310
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006311 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006312
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006313 if (static_cast<uint32_t>(indices.length()) < limit) {
6314 indices.Add(subject_length);
6315 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006316
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006317 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006318
6319 // Create JSArray of substrings separated by separator.
6320 int part_count = indices.length();
6321
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006322 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006323 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006324 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006325 result->set_length(Smi::FromInt(part_count));
6326
6327 ASSERT(result->HasFastElements());
6328
6329 if (part_count == 1 && indices.at(0) == subject_length) {
6330 FixedArray::cast(result->elements())->set(0, *subject);
6331 return *result;
6332 }
6333
6334 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6335 int part_start = 0;
6336 for (int i = 0; i < part_count; i++) {
6337 HandleScope local_loop_handle;
6338 int part_end = indices.at(i);
6339 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006340 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006341 elements->set(i, *substring);
6342 part_start = part_end + pattern_length;
6343 }
6344
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006345 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006346 if (result->HasFastElements()) {
6347 StringSplitCache::Enter(isolate->heap(),
6348 isolate->heap()->string_split_cache(),
6349 *subject,
6350 *pattern,
6351 *elements);
6352 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006353 }
6354
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006355 return *result;
6356}
6357
6358
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006359// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006360// one-char strings in the cache. Gives up on the first char that is
6361// not in the cache and fills the remainder with smi zeros. Returns
6362// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006363static int CopyCachedAsciiCharsToArray(Heap* heap,
6364 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006365 FixedArray* elements,
6366 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006367 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006368 FixedArray* ascii_cache = heap->single_character_string_cache();
6369 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006370 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006371 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006372 for (i = 0; i < length; ++i) {
6373 Object* value = ascii_cache->get(chars[i]);
6374 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006375 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006376 }
6377 if (i < length) {
6378 ASSERT(Smi::FromInt(0) == 0);
6379 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6380 }
6381#ifdef DEBUG
6382 for (int j = 0; j < length; ++j) {
6383 Object* element = elements->get(j);
6384 ASSERT(element == Smi::FromInt(0) ||
6385 (element->IsString() && String::cast(element)->LooksValid()));
6386 }
6387#endif
6388 return i;
6389}
6390
6391
6392// Converts a String to JSArray.
6393// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006394RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006395 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006396 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006397 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006398 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006399
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006400 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006401 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006402
6403 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006404 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006405 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006406 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006407 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006408 { MaybeObject* maybe_obj =
6409 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006410 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6411 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006412 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006413 String::FlatContent content = s->GetFlatContent();
6414 if (content.IsAscii()) {
6415 Vector<const char> chars = content.ToAsciiVector();
6416 // Note, this will initialize all elements (not only the prefix)
6417 // to prevent GC from seeing partially initialized array.
6418 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6419 chars.start(),
6420 *elements,
6421 length);
6422 } else {
6423 MemsetPointer(elements->data_start(),
6424 isolate->heap()->undefined_value(),
6425 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006426 }
6427 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006428 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006429 }
6430 for (int i = position; i < length; ++i) {
6431 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6432 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006433 }
6434
6435#ifdef DEBUG
6436 for (int i = 0; i < length; ++i) {
6437 ASSERT(String::cast(elements->get(i))->length() == 1);
6438 }
6439#endif
6440
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006441 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006442}
6443
6444
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006445RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006446 NoHandleAllocation ha;
6447 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006448 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006449 return value->ToObject();
6450}
6451
6452
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006453bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006454 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006455 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006456 return char_length == 0;
6457}
6458
6459
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006460RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006461 NoHandleAllocation ha;
6462 ASSERT(args.length() == 1);
6463
6464 Object* number = args[0];
6465 RUNTIME_ASSERT(number->IsNumber());
6466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006467 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006468}
6469
6470
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006471RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006472 NoHandleAllocation ha;
6473 ASSERT(args.length() == 1);
6474
6475 Object* number = args[0];
6476 RUNTIME_ASSERT(number->IsNumber());
6477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006479}
6480
6481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006482RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006483 NoHandleAllocation ha;
6484 ASSERT(args.length() == 1);
6485
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006486 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006487
6488 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6489 if (number > 0 && number <= Smi::kMaxValue) {
6490 return Smi::FromInt(static_cast<int>(number));
6491 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006492 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006493}
6494
6495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006496RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006497 NoHandleAllocation ha;
6498 ASSERT(args.length() == 1);
6499
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006500 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006501
6502 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6503 if (number > 0 && number <= Smi::kMaxValue) {
6504 return Smi::FromInt(static_cast<int>(number));
6505 }
6506
6507 double double_value = DoubleToInteger(number);
6508 // Map both -0 and +0 to +0.
6509 if (double_value == 0) double_value = 0;
6510
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006511 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006512}
6513
6514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006515RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006516 NoHandleAllocation ha;
6517 ASSERT(args.length() == 1);
6518
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006519 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006520 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006521}
6522
6523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006524RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525 NoHandleAllocation ha;
6526 ASSERT(args.length() == 1);
6527
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006528 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006529
6530 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6531 if (number > 0 && number <= Smi::kMaxValue) {
6532 return Smi::FromInt(static_cast<int>(number));
6533 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006534 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006535}
6536
6537
ager@chromium.org870a0b62008-11-04 11:43:05 +00006538// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6539// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006540RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006541 NoHandleAllocation ha;
6542 ASSERT(args.length() == 1);
6543
6544 Object* obj = args[0];
6545 if (obj->IsSmi()) {
6546 return obj;
6547 }
6548 if (obj->IsHeapNumber()) {
6549 double value = HeapNumber::cast(obj)->value();
6550 int int_value = FastD2I(value);
6551 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6552 return Smi::FromInt(int_value);
6553 }
6554 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006555 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006556}
6557
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006559RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006560 NoHandleAllocation ha;
6561 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006562 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006563}
6564
6565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006566RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567 NoHandleAllocation ha;
6568 ASSERT(args.length() == 2);
6569
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006570 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6571 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006572 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573}
6574
6575
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006576RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006577 NoHandleAllocation ha;
6578 ASSERT(args.length() == 2);
6579
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006580 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6581 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006582 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583}
6584
6585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006586RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587 NoHandleAllocation ha;
6588 ASSERT(args.length() == 2);
6589
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006590 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6591 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006592 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593}
6594
6595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006596RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006597 NoHandleAllocation ha;
6598 ASSERT(args.length() == 1);
6599
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006600 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006601 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006602}
6603
6604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006605RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006606 NoHandleAllocation ha;
6607 ASSERT(args.length() == 0);
6608
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006609 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006610}
6611
6612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006613RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006614 NoHandleAllocation ha;
6615 ASSERT(args.length() == 2);
6616
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006617 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6618 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006619 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006620}
6621
6622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006623RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006624 NoHandleAllocation ha;
6625 ASSERT(args.length() == 2);
6626
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006627 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6628 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629
ager@chromium.org3811b432009-10-28 14:53:37 +00006630 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006631 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006632 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633}
6634
6635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006636RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637 NoHandleAllocation ha;
6638 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006639 CONVERT_ARG_CHECKED(String, str1, 0);
6640 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006641 isolate->counters()->string_add_runtime()->Increment();
6642 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006643}
6644
6645
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006646template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006647static inline void StringBuilderConcatHelper(String* special,
6648 sinkchar* sink,
6649 FixedArray* fixed_array,
6650 int array_length) {
6651 int position = 0;
6652 for (int i = 0; i < array_length; i++) {
6653 Object* element = fixed_array->get(i);
6654 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006655 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006656 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006657 int pos;
6658 int len;
6659 if (encoded_slice > 0) {
6660 // Position and length encoded in one smi.
6661 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6662 len = StringBuilderSubstringLength::decode(encoded_slice);
6663 } else {
6664 // Position and length encoded in two smis.
6665 Object* obj = fixed_array->get(++i);
6666 ASSERT(obj->IsSmi());
6667 pos = Smi::cast(obj)->value();
6668 len = -encoded_slice;
6669 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006670 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006671 sink + position,
6672 pos,
6673 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006674 position += len;
6675 } else {
6676 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006677 int element_length = string->length();
6678 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006679 position += element_length;
6680 }
6681 }
6682}
6683
6684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006685RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006687 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006688 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006689 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006690 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006691 return Failure::OutOfMemoryException();
6692 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006693 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006694 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006695
6696 // This assumption is used by the slice encoding in one or two smis.
6697 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6698
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006699 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006700 if (maybe_result->IsFailure()) return maybe_result;
6701
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006702 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006703 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006704 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705 }
6706 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006707 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006708 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006709 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006710
6711 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006712 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006713 } else if (array_length == 1) {
6714 Object* first = fixed_array->get(0);
6715 if (first->IsString()) return first;
6716 }
6717
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006718 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006719 int position = 0;
6720 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006721 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006722 Object* elt = fixed_array->get(i);
6723 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006724 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006725 int smi_value = Smi::cast(elt)->value();
6726 int pos;
6727 int len;
6728 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006729 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006730 pos = StringBuilderSubstringPosition::decode(smi_value);
6731 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006732 } else {
6733 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006734 len = -smi_value;
6735 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006736 i++;
6737 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006738 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006739 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006740 Object* next_smi = fixed_array->get(i);
6741 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006742 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006743 }
6744 pos = Smi::cast(next_smi)->value();
6745 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006746 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006747 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006748 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006749 ASSERT(pos >= 0);
6750 ASSERT(len >= 0);
6751 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006753 }
6754 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006755 } else if (elt->IsString()) {
6756 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006757 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006758 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006759 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006761 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006763 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006765 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006766 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006767 return Failure::OutOfMemoryException();
6768 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006769 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770 }
6771
6772 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006773 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006774
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006775 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006776 { MaybeObject* maybe_object =
6777 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006778 if (!maybe_object->ToObject(&object)) return maybe_object;
6779 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006780 SeqAsciiString* answer = SeqAsciiString::cast(object);
6781 StringBuilderConcatHelper(special,
6782 answer->GetChars(),
6783 fixed_array,
6784 array_length);
6785 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006786 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006787 { MaybeObject* maybe_object =
6788 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006789 if (!maybe_object->ToObject(&object)) return maybe_object;
6790 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006791 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6792 StringBuilderConcatHelper(special,
6793 answer->GetChars(),
6794 fixed_array,
6795 array_length);
6796 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006797 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006798}
6799
6800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006801RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006802 NoHandleAllocation ha;
6803 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006804 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006805 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006806 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006807 return Failure::OutOfMemoryException();
6808 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006809 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006810 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006811
6812 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006813 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006814 }
6815 FixedArray* fixed_array = FixedArray::cast(array->elements());
6816 if (fixed_array->length() < array_length) {
6817 array_length = fixed_array->length();
6818 }
6819
6820 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006821 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006822 } else if (array_length == 1) {
6823 Object* first = fixed_array->get(0);
6824 if (first->IsString()) return first;
6825 }
6826
6827 int separator_length = separator->length();
6828 int max_nof_separators =
6829 (String::kMaxLength + separator_length - 1) / separator_length;
6830 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006831 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006832 return Failure::OutOfMemoryException();
6833 }
6834 int length = (array_length - 1) * separator_length;
6835 for (int i = 0; i < array_length; i++) {
6836 Object* element_obj = fixed_array->get(i);
6837 if (!element_obj->IsString()) {
6838 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006839 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006840 }
6841 String* element = String::cast(element_obj);
6842 int increment = element->length();
6843 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006844 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006845 return Failure::OutOfMemoryException();
6846 }
6847 length += increment;
6848 }
6849
6850 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006851 { MaybeObject* maybe_object =
6852 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006853 if (!maybe_object->ToObject(&object)) return maybe_object;
6854 }
6855 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6856
6857 uc16* sink = answer->GetChars();
6858#ifdef DEBUG
6859 uc16* end = sink + length;
6860#endif
6861
6862 String* first = String::cast(fixed_array->get(0));
6863 int first_length = first->length();
6864 String::WriteToFlat(first, sink, 0, first_length);
6865 sink += first_length;
6866
6867 for (int i = 1; i < array_length; i++) {
6868 ASSERT(sink + separator_length <= end);
6869 String::WriteToFlat(separator, sink, 0, separator_length);
6870 sink += separator_length;
6871
6872 String* element = String::cast(fixed_array->get(i));
6873 int element_length = element->length();
6874 ASSERT(sink + element_length <= end);
6875 String::WriteToFlat(element, sink, 0, element_length);
6876 sink += element_length;
6877 }
6878 ASSERT(sink == end);
6879
6880 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6881 return answer;
6882}
6883
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006884template <typename Char>
6885static void JoinSparseArrayWithSeparator(FixedArray* elements,
6886 int elements_length,
6887 uint32_t array_length,
6888 String* separator,
6889 Vector<Char> buffer) {
6890 int previous_separator_position = 0;
6891 int separator_length = separator->length();
6892 int cursor = 0;
6893 for (int i = 0; i < elements_length; i += 2) {
6894 int position = NumberToInt32(elements->get(i));
6895 String* string = String::cast(elements->get(i + 1));
6896 int string_length = string->length();
6897 if (string->length() > 0) {
6898 while (previous_separator_position < position) {
6899 String::WriteToFlat<Char>(separator, &buffer[cursor],
6900 0, separator_length);
6901 cursor += separator_length;
6902 previous_separator_position++;
6903 }
6904 String::WriteToFlat<Char>(string, &buffer[cursor],
6905 0, string_length);
6906 cursor += string->length();
6907 }
6908 }
6909 if (separator_length > 0) {
6910 // Array length must be representable as a signed 32-bit number,
6911 // otherwise the total string length would have been too large.
6912 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6913 int last_array_index = static_cast<int>(array_length - 1);
6914 while (previous_separator_position < last_array_index) {
6915 String::WriteToFlat<Char>(separator, &buffer[cursor],
6916 0, separator_length);
6917 cursor += separator_length;
6918 previous_separator_position++;
6919 }
6920 }
6921 ASSERT(cursor <= buffer.length());
6922}
6923
6924
6925RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6926 NoHandleAllocation ha;
6927 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006928 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006929 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6930 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006931 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006932 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006933 // elements_array is fast-mode JSarray of alternating positions
6934 // (increasing order) and strings.
6935 // array_length is length of original array (used to add separators);
6936 // separator is string to put between elements. Assumed to be non-empty.
6937
6938 // Find total length of join result.
6939 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006940 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006941 int max_string_length;
6942 if (is_ascii) {
6943 max_string_length = SeqAsciiString::kMaxLength;
6944 } else {
6945 max_string_length = SeqTwoByteString::kMaxLength;
6946 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006947 bool overflow = false;
6948 CONVERT_NUMBER_CHECKED(int, elements_length,
6949 Int32, elements_array->length());
6950 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6951 FixedArray* elements = FixedArray::cast(elements_array->elements());
6952 for (int i = 0; i < elements_length; i += 2) {
6953 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006954 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6955 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006956 int length = string->length();
6957 if (is_ascii && !string->IsAsciiRepresentation()) {
6958 is_ascii = false;
6959 max_string_length = SeqTwoByteString::kMaxLength;
6960 }
6961 if (length > max_string_length ||
6962 max_string_length - length < string_length) {
6963 overflow = true;
6964 break;
6965 }
6966 string_length += length;
6967 }
6968 int separator_length = separator->length();
6969 if (!overflow && separator_length > 0) {
6970 if (array_length <= 0x7fffffffu) {
6971 int separator_count = static_cast<int>(array_length) - 1;
6972 int remaining_length = max_string_length - string_length;
6973 if ((remaining_length / separator_length) >= separator_count) {
6974 string_length += separator_length * (array_length - 1);
6975 } else {
6976 // Not room for the separators within the maximal string length.
6977 overflow = true;
6978 }
6979 } else {
6980 // Nonempty separator and at least 2^31-1 separators necessary
6981 // means that the string is too large to create.
6982 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6983 overflow = true;
6984 }
6985 }
6986 if (overflow) {
6987 // Throw OutOfMemory exception for creating too large a string.
6988 V8::FatalProcessOutOfMemory("Array join result too large.");
6989 }
6990
6991 if (is_ascii) {
6992 MaybeObject* result_allocation =
6993 isolate->heap()->AllocateRawAsciiString(string_length);
6994 if (result_allocation->IsFailure()) return result_allocation;
6995 SeqAsciiString* result_string =
6996 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6997 JoinSparseArrayWithSeparator<char>(elements,
6998 elements_length,
6999 array_length,
7000 separator,
7001 Vector<char>(result_string->GetChars(),
7002 string_length));
7003 return result_string;
7004 } else {
7005 MaybeObject* result_allocation =
7006 isolate->heap()->AllocateRawTwoByteString(string_length);
7007 if (result_allocation->IsFailure()) return result_allocation;
7008 SeqTwoByteString* result_string =
7009 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7010 JoinSparseArrayWithSeparator<uc16>(elements,
7011 elements_length,
7012 array_length,
7013 separator,
7014 Vector<uc16>(result_string->GetChars(),
7015 string_length));
7016 return result_string;
7017 }
7018}
7019
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007021RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022 NoHandleAllocation ha;
7023 ASSERT(args.length() == 2);
7024
7025 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7026 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007027 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007028}
7029
7030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007031RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007032 NoHandleAllocation ha;
7033 ASSERT(args.length() == 2);
7034
7035 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7036 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007037 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007038}
7039
7040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007041RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007042 NoHandleAllocation ha;
7043 ASSERT(args.length() == 2);
7044
7045 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7046 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007047 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007048}
7049
7050
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007051RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007052 NoHandleAllocation ha;
7053 ASSERT(args.length() == 1);
7054
7055 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007056 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007057}
7058
7059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007060RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061 NoHandleAllocation ha;
7062 ASSERT(args.length() == 2);
7063
7064 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7065 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007066 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007067}
7068
7069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007070RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071 NoHandleAllocation ha;
7072 ASSERT(args.length() == 2);
7073
7074 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7075 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007076 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077}
7078
7079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007080RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007081 NoHandleAllocation ha;
7082 ASSERT(args.length() == 2);
7083
7084 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7085 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007086 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007087}
7088
7089
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007090RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007091 NoHandleAllocation ha;
7092 ASSERT(args.length() == 2);
7093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007094 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7095 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007096 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7097 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7098 if (x == y) return Smi::FromInt(EQUAL);
7099 Object* result;
7100 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7101 result = Smi::FromInt(EQUAL);
7102 } else {
7103 result = Smi::FromInt(NOT_EQUAL);
7104 }
7105 return result;
7106}
7107
7108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007109RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110 NoHandleAllocation ha;
7111 ASSERT(args.length() == 2);
7112
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007113 CONVERT_ARG_CHECKED(String, x, 0);
7114 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007115
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007116 bool not_equal = !x->Equals(y);
7117 // This is slightly convoluted because the value that signifies
7118 // equality is 0 and inequality is 1 so we have to negate the result
7119 // from String::Equals.
7120 ASSERT(not_equal == 0 || not_equal == 1);
7121 STATIC_CHECK(EQUAL == 0);
7122 STATIC_CHECK(NOT_EQUAL == 1);
7123 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007124}
7125
7126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007127RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007128 NoHandleAllocation ha;
7129 ASSERT(args.length() == 3);
7130
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007131 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7132 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007133 if (isnan(x) || isnan(y)) return args[2];
7134 if (x == y) return Smi::FromInt(EQUAL);
7135 if (isless(x, y)) return Smi::FromInt(LESS);
7136 return Smi::FromInt(GREATER);
7137}
7138
7139
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007140// Compare two Smis as if they were converted to strings and then
7141// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007142RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007143 NoHandleAllocation ha;
7144 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007145 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7146 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007147
7148 // If the integers are equal so are the string representations.
7149 if (x_value == y_value) return Smi::FromInt(EQUAL);
7150
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007151 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007152 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007153 if (x_value == 0 || y_value == 0)
7154 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007155
ager@chromium.org32912102009-01-16 10:38:43 +00007156 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007157 // smallest because the char code of '-' is less than the char code
7158 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007159
7160 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7161 // architectures using 32-bit Smis.
7162 uint32_t x_scaled = x_value;
7163 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007164 if (x_value < 0 || y_value < 0) {
7165 if (y_value >= 0) return Smi::FromInt(LESS);
7166 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007167 x_scaled = -x_value;
7168 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007169 }
7170
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007171 static const uint32_t kPowersOf10[] = {
7172 1, 10, 100, 1000, 10*1000, 100*1000,
7173 1000*1000, 10*1000*1000, 100*1000*1000,
7174 1000*1000*1000
7175 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007176
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007177 // If the integers have the same number of decimal digits they can be
7178 // compared directly as the numeric order is the same as the
7179 // lexicographic order. If one integer has fewer digits, it is scaled
7180 // by some power of 10 to have the same number of digits as the longer
7181 // integer. If the scaled integers are equal it means the shorter
7182 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007183
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007184 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7185 int x_log2 = IntegerLog2(x_scaled);
7186 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7187 x_log10 -= x_scaled < kPowersOf10[x_log10];
7188
7189 int y_log2 = IntegerLog2(y_scaled);
7190 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7191 y_log10 -= y_scaled < kPowersOf10[y_log10];
7192
7193 int tie = EQUAL;
7194
7195 if (x_log10 < y_log10) {
7196 // X has fewer digits. We would like to simply scale up X but that
7197 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7198 // be scaled up to 9_000_000_000. So we scale up by the next
7199 // smallest power and scale down Y to drop one digit. It is OK to
7200 // drop one digit from the longer integer since the final digit is
7201 // past the length of the shorter integer.
7202 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7203 y_scaled /= 10;
7204 tie = LESS;
7205 } else if (y_log10 < x_log10) {
7206 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7207 x_scaled /= 10;
7208 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007209 }
7210
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007211 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7212 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7213 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007214}
7215
7216
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007217static Object* StringInputBufferCompare(RuntimeState* state,
7218 String* x,
7219 String* y) {
7220 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7221 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007222 bufx.Reset(x);
7223 bufy.Reset(y);
7224 while (bufx.has_more() && bufy.has_more()) {
7225 int d = bufx.GetNext() - bufy.GetNext();
7226 if (d < 0) return Smi::FromInt(LESS);
7227 else if (d > 0) return Smi::FromInt(GREATER);
7228 }
7229
7230 // x is (non-trivial) prefix of y:
7231 if (bufy.has_more()) return Smi::FromInt(LESS);
7232 // y is prefix of x:
7233 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7234}
7235
7236
7237static Object* FlatStringCompare(String* x, String* y) {
7238 ASSERT(x->IsFlat());
7239 ASSERT(y->IsFlat());
7240 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7241 int prefix_length = x->length();
7242 if (y->length() < prefix_length) {
7243 prefix_length = y->length();
7244 equal_prefix_result = Smi::FromInt(GREATER);
7245 } else if (y->length() > prefix_length) {
7246 equal_prefix_result = Smi::FromInt(LESS);
7247 }
7248 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007249 String::FlatContent x_content = x->GetFlatContent();
7250 String::FlatContent y_content = y->GetFlatContent();
7251 if (x_content.IsAscii()) {
7252 Vector<const char> x_chars = x_content.ToAsciiVector();
7253 if (y_content.IsAscii()) {
7254 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007255 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007256 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007257 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007258 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7259 }
7260 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007261 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7262 if (y_content.IsAscii()) {
7263 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007264 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7265 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007266 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007267 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7268 }
7269 }
7270 Object* result;
7271 if (r == 0) {
7272 result = equal_prefix_result;
7273 } else {
7274 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7275 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007276 ASSERT(result ==
7277 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007278 return result;
7279}
7280
7281
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007282RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283 NoHandleAllocation ha;
7284 ASSERT(args.length() == 2);
7285
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007286 CONVERT_ARG_CHECKED(String, x, 0);
7287 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007288
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007289 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007290
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007291 // A few fast case tests before we flatten.
7292 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007293 if (y->length() == 0) {
7294 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007295 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007296 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007297 return Smi::FromInt(LESS);
7298 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007299
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007300 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007301 if (d < 0) return Smi::FromInt(LESS);
7302 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007303
lrn@chromium.org303ada72010-10-27 09:33:13 +00007304 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007305 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007306 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7307 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007308 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007309 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7310 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007312 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314}
7315
7316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007317RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007318 NoHandleAllocation ha;
7319 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007320 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007322 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007323 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007324}
7325
7326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007327RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007328 NoHandleAllocation ha;
7329 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007330 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007331
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007332 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007333 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007334}
7335
7336
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007337RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007338 NoHandleAllocation ha;
7339 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007342 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007343 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344}
7345
7346
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007347static const double kPiDividedBy4 = 0.78539816339744830962;
7348
7349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007350RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007351 NoHandleAllocation ha;
7352 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007353 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007355 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7356 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007357 double result;
7358 if (isinf(x) && isinf(y)) {
7359 // Make sure that the result in case of two infinite arguments
7360 // is a multiple of Pi / 4. The sign of the result is determined
7361 // by the first argument (x) and the sign of the second argument
7362 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363 int multiplier = (x < 0) ? -1 : 1;
7364 if (y < 0) multiplier *= 3;
7365 result = multiplier * kPiDividedBy4;
7366 } else {
7367 result = atan2(x, y);
7368 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007369 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370}
7371
7372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007373RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374 NoHandleAllocation ha;
7375 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007378 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007379 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380}
7381
7382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007383RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384 NoHandleAllocation ha;
7385 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007388 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007389 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390}
7391
7392
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007393RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007394 NoHandleAllocation ha;
7395 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007396 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007398 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400}
7401
7402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007403RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404 NoHandleAllocation ha;
7405 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007408 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410}
7411
7412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007413RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414 NoHandleAllocation ha;
7415 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007416 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007417
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007418 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007419 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420}
7421
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007422// Slow version of Math.pow. We check for fast paths for special cases.
7423// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007424RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007425 NoHandleAllocation ha;
7426 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007427 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007428
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007429 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007430
7431 // If the second argument is a smi, it is much faster to call the
7432 // custom powi() function than the generic pow().
7433 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007434 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007435 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007436 }
7437
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007438 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007439 int y_int = static_cast<int>(y);
7440 double result;
7441 if (y == y_int) {
7442 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7443 } else if (y == 0.5) {
7444 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7445 } else if (y == -0.5) {
7446 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7447 } else {
7448 result = power_double_double(x, y);
7449 }
7450 if (isnan(result)) return isolate->heap()->nan_value();
7451 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007452}
7453
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007454// Fast version of Math.pow if we know that y is not an integer and y is not
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007455// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007456RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007457 NoHandleAllocation ha;
7458 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007459 isolate->counters()->math_pow()->Increment();
7460
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007461 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7462 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007463 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007464 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007465 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007466 double result = power_double_double(x, y);
7467 if (isnan(result)) return isolate->heap()->nan_value();
7468 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007469 }
7470}
7471
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007472
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007473RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007474 NoHandleAllocation ha;
7475 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007476 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007477
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007478 if (!args[0]->IsHeapNumber()) {
7479 // Must be smi. Return the argument unchanged for all the other types
7480 // to make fuzz-natives test happy.
7481 return args[0];
7482 }
7483
7484 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7485
7486 double value = number->value();
7487 int exponent = number->get_exponent();
7488 int sign = number->get_sign();
7489
danno@chromium.org160a7b02011-04-18 15:51:38 +00007490 if (exponent < -1) {
7491 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7492 if (sign) return isolate->heap()->minus_zero_value();
7493 return Smi::FromInt(0);
7494 }
7495
7496 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7497 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007498 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007499 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007500 return Smi::FromInt(static_cast<int>(value + 0.5));
7501 }
7502
7503 // If the magnitude is big enough, there's no place for fraction part. If we
7504 // try to add 0.5 to this number, 1.0 will be added instead.
7505 if (exponent >= 52) {
7506 return number;
7507 }
7508
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007509 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007510
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007511 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007512 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007513}
7514
7515
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007516RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007517 NoHandleAllocation ha;
7518 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007519 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007520
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007521 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007522 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007523}
7524
7525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007526RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007527 NoHandleAllocation ha;
7528 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007529 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007530
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007531 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007532 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007533}
7534
7535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007536RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007537 NoHandleAllocation ha;
7538 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007539 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007540
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007541 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007542 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007543}
7544
7545
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007546RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007547 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007548 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007549
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007550 CONVERT_SMI_ARG_CHECKED(year, 0);
7551 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007552
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007553 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007554}
7555
7556
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007557RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7558 HandleScope scope(isolate);
7559 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007560
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007561 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7562 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7563 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007564
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007565 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007566
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007567 Object* value = NULL;
7568 bool is_value_nan = false;
7569 if (isnan(time)) {
7570 value = isolate->heap()->nan_value();
7571 is_value_nan = true;
7572 } else if (!is_utc &&
7573 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7574 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7575 value = isolate->heap()->nan_value();
7576 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007577 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007578 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7579 if (time < -DateCache::kMaxTimeInMs ||
7580 time > DateCache::kMaxTimeInMs) {
7581 value = isolate->heap()->nan_value();
7582 is_value_nan = true;
7583 } else {
7584 MaybeObject* maybe_result =
7585 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7586 if (!maybe_result->ToObject(&value)) return maybe_result;
7587 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007588 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007589 date->SetValue(value, is_value_nan);
7590 return *date;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007591}
7592
7593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007594RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007595 HandleScope scope(isolate);
7596 ASSERT(args.length() == 3);
7597
7598 Handle<JSFunction> callee = args.at<JSFunction>(0);
7599 Object** parameters = reinterpret_cast<Object**>(args[1]);
7600 const int argument_count = Smi::cast(args[2])->value();
7601
7602 Handle<JSObject> result =
7603 isolate->factory()->NewArgumentsObject(callee, argument_count);
7604 // Allocate the elements if needed.
7605 int parameter_count = callee->shared()->formal_parameter_count();
7606 if (argument_count > 0) {
7607 if (parameter_count > 0) {
7608 int mapped_count = Min(argument_count, parameter_count);
7609 Handle<FixedArray> parameter_map =
7610 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7611 parameter_map->set_map(
7612 isolate->heap()->non_strict_arguments_elements_map());
7613
7614 Handle<Map> old_map(result->map());
7615 Handle<Map> new_map =
7616 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007617 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007618
7619 result->set_map(*new_map);
7620 result->set_elements(*parameter_map);
7621
7622 // Store the context and the arguments array at the beginning of the
7623 // parameter map.
7624 Handle<Context> context(isolate->context());
7625 Handle<FixedArray> arguments =
7626 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7627 parameter_map->set(0, *context);
7628 parameter_map->set(1, *arguments);
7629
7630 // Loop over the actual parameters backwards.
7631 int index = argument_count - 1;
7632 while (index >= mapped_count) {
7633 // These go directly in the arguments array and have no
7634 // corresponding slot in the parameter map.
7635 arguments->set(index, *(parameters - index - 1));
7636 --index;
7637 }
7638
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007639 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007640 while (index >= 0) {
7641 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007642 Handle<String> name(scope_info->ParameterName(index));
7643 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007644 bool duplicate = false;
7645 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007646 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007647 duplicate = true;
7648 break;
7649 }
7650 }
7651
7652 if (duplicate) {
7653 // This goes directly in the arguments array with a hole in the
7654 // parameter map.
7655 arguments->set(index, *(parameters - index - 1));
7656 parameter_map->set_the_hole(index + 2);
7657 } else {
7658 // The context index goes in the parameter map with a hole in the
7659 // arguments array.
7660 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007661 for (int j = 0; j < context_local_count; ++j) {
7662 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007663 context_index = j;
7664 break;
7665 }
7666 }
7667 ASSERT(context_index >= 0);
7668 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007669 parameter_map->set(index + 2, Smi::FromInt(
7670 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007671 }
7672
7673 --index;
7674 }
7675 } else {
7676 // If there is no aliasing, the arguments object elements are not
7677 // special in any way.
7678 Handle<FixedArray> elements =
7679 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7680 result->set_elements(*elements);
7681 for (int i = 0; i < argument_count; ++i) {
7682 elements->set(i, *(parameters - i - 1));
7683 }
7684 }
7685 }
7686 return *result;
7687}
7688
7689
7690RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007691 NoHandleAllocation ha;
7692 ASSERT(args.length() == 3);
7693
7694 JSFunction* callee = JSFunction::cast(args[0]);
7695 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007696 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007697
lrn@chromium.org303ada72010-10-27 09:33:13 +00007698 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007699 { MaybeObject* maybe_result =
7700 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007701 if (!maybe_result->ToObject(&result)) return maybe_result;
7702 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007703 // Allocate the elements if needed.
7704 if (length > 0) {
7705 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007706 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007707 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007708 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7709 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007710
7711 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007712 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007713 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007714 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007715
7716 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007717 for (int i = 0; i < length; i++) {
7718 array->set(i, *--parameters, mode);
7719 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007720 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007721 }
7722 return result;
7723}
7724
7725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007726RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007727 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007728 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007729 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
7730 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
7731 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007732
whesse@chromium.org7b260152011-06-20 15:33:18 +00007733 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007734 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007735 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007736 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007737 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7738 context,
7739 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007740 return *result;
7741}
7742
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007743
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007744// Find the arguments of the JavaScript function invocation that called
7745// into C++ code. Collect these in a newly allocated array of handles (possibly
7746// prefixed by a number of empty handles).
7747static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7748 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007749 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007750 // Find frame containing arguments passed to the caller.
7751 JavaScriptFrameIterator it;
7752 JavaScriptFrame* frame = it.frame();
7753 List<JSFunction*> functions(2);
7754 frame->GetFunctions(&functions);
7755 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007756 int inlined_jsframe_index = functions.length() - 1;
7757 JSFunction* inlined_function = functions[inlined_jsframe_index];
7758 Vector<SlotRef> args_slots =
7759 SlotRef::ComputeSlotMappingForArguments(
7760 frame,
7761 inlined_jsframe_index,
7762 inlined_function->shared()->formal_parameter_count());
7763
7764 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007765
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007766 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007767 SmartArrayPointer<Handle<Object> > param_data(
7768 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007769 for (int i = 0; i < args_count; i++) {
7770 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007771 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007772 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007773
7774 args_slots.Dispose();
7775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007776 return param_data;
7777 } else {
7778 it.AdvanceToArgumentsFrame();
7779 frame = it.frame();
7780 int args_count = frame->ComputeParametersCount();
7781
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007782 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007783 SmartArrayPointer<Handle<Object> > param_data(
7784 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007785 for (int i = 0; i < args_count; i++) {
7786 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007787 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007788 }
7789 return param_data;
7790 }
7791}
7792
7793
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007794RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7795 HandleScope scope(isolate);
7796 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007797 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007798 RUNTIME_ASSERT(args[3]->IsNumber());
7799 Handle<Object> bindee = args.at<Object>(1);
7800
7801 // TODO(lrn): Create bound function in C++ code from premade shared info.
7802 bound_function->shared()->set_bound(true);
7803 // Get all arguments of calling function (Function.prototype.bind).
7804 int argc = 0;
7805 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7806 // Don't count the this-arg.
7807 if (argc > 0) {
7808 ASSERT(*arguments[0] == args[2]);
7809 argc--;
7810 } else {
7811 ASSERT(args[2]->IsUndefined());
7812 }
7813 // Initialize array of bindings (function, this, and any existing arguments
7814 // if the function was already bound).
7815 Handle<FixedArray> new_bindings;
7816 int i;
7817 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7818 Handle<FixedArray> old_bindings(
7819 JSFunction::cast(*bindee)->function_bindings());
7820 new_bindings =
7821 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7822 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7823 i = 0;
7824 for (int n = old_bindings->length(); i < n; i++) {
7825 new_bindings->set(i, old_bindings->get(i));
7826 }
7827 } else {
7828 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7829 new_bindings = isolate->factory()->NewFixedArray(array_size);
7830 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7831 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7832 i = 2;
7833 }
7834 // Copy arguments, skipping the first which is "this_arg".
7835 for (int j = 0; j < argc; j++, i++) {
7836 new_bindings->set(i, *arguments[j + 1]);
7837 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007838 new_bindings->set_map_no_write_barrier(
7839 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007840 bound_function->set_function_bindings(*new_bindings);
7841
7842 // Update length.
7843 Handle<String> length_symbol = isolate->factory()->length_symbol();
7844 Handle<Object> new_length(args.at<Object>(3));
7845 PropertyAttributes attr =
7846 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
7847 ForceSetProperty(bound_function, length_symbol, new_length, attr);
7848 return *bound_function;
7849}
7850
7851
7852RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
7853 HandleScope handles(isolate);
7854 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007855 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007856 if (callable->IsJSFunction()) {
7857 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
7858 if (function->shared()->bound()) {
7859 Handle<FixedArray> bindings(function->function_bindings());
7860 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
7861 return *isolate->factory()->NewJSArrayWithElements(bindings);
7862 }
7863 }
7864 return isolate->heap()->undefined_value();
7865}
7866
7867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007868RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007869 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007870 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007871 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007872 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007873 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007874
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007875 // The argument is a bound function. Extract its bound arguments
7876 // and callable.
7877 Handle<FixedArray> bound_args =
7878 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7879 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7880 Handle<Object> bound_function(
7881 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7882 ASSERT(!bound_function->IsJSFunction() ||
7883 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007885 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007886 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007887 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007888 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007889 param_data[i] = Handle<Object>(bound_args->get(
7890 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007891 }
7892
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007893 if (!bound_function->IsJSFunction()) {
7894 bool exception_thrown;
7895 bound_function = Execution::TryGetConstructorDelegate(bound_function,
7896 &exception_thrown);
7897 if (exception_thrown) return Failure::Exception();
7898 }
7899 ASSERT(bound_function->IsJSFunction());
7900
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007901 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007902 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007903 Execution::New(Handle<JSFunction>::cast(bound_function),
7904 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007905 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007906 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007907 }
7908 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007909 return *result;
7910}
7911
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007912
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007913static void TrySettingInlineConstructStub(Isolate* isolate,
7914 Handle<JSFunction> function) {
7915 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007916 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007917 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007918 }
7919 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007920 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007921 Handle<Code> code = compiler.CompileConstructStub(function);
7922 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007923 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007924}
7925
7926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007927RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007928 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007929 ASSERT(args.length() == 1);
7930
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007931 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007932
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007933 // If the constructor isn't a proper function we throw a type error.
7934 if (!constructor->IsJSFunction()) {
7935 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7936 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007937 isolate->factory()->NewTypeError("not_constructor", arguments);
7938 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007939 }
7940
7941 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007942
7943 // If function should not have prototype, construction is not allowed. In this
7944 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007945 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007946 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7947 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007948 isolate->factory()->NewTypeError("not_constructor", arguments);
7949 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007950 }
7951
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007952#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007953 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007954 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007955 if (debug->StepInActive()) {
7956 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007957 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007958#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007959
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007960 if (function->has_initial_map()) {
7961 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007962 // The 'Function' function ignores the receiver object when
7963 // called using 'new' and creates a new JSFunction object that
7964 // is returned. The receiver object is only used for error
7965 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007966 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007967 // allocate JSFunctions since it does not properly initialize
7968 // the shared part of the function. Since the receiver is
7969 // ignored anyway, we use the global object as the receiver
7970 // instead of a new JSFunction object. This way, errors are
7971 // reported the same way whether or not 'Function' is called
7972 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007973 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007974 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007975 }
7976
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007977 // The function should be compiled for the optimization hints to be
7978 // available. We cannot use EnsureCompiled because that forces a
7979 // compilation through the shared function info which makes it
7980 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007981 if (!function->is_compiled()) {
7982 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
7983 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007984
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007985 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007986 if (!function->has_initial_map() &&
7987 shared->IsInobjectSlackTrackingInProgress()) {
7988 // The tracking is already in progress for another function. We can only
7989 // track one initial_map at a time, so we force the completion before the
7990 // function is called as a constructor for the first time.
7991 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007992 }
7993
7994 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007995 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7996 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007997 // Delay setting the stub if inobject slack tracking is in progress.
7998 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007999 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008000 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008001
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008002 isolate->counters()->constructed_objects()->Increment();
8003 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008004
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008005 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008006}
8007
8008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008009RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008010 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008011 ASSERT(args.length() == 1);
8012
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008013 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008014 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008015 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008017 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008018}
8019
8020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008021RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008022 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008023 ASSERT(args.length() == 1);
8024
8025 Handle<JSFunction> function = args.at<JSFunction>(0);
8026#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008027 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008028 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008029 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008030 PrintF("]\n");
8031 }
8032#endif
8033
lrn@chromium.org34e60782011-09-15 07:25:40 +00008034 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008035 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008036 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008037 return Failure::Exception();
8038 }
8039
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008040 // All done. Return the compiled code.
8041 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008042 return function->code();
8043}
8044
8045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008046RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008047 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008048 ASSERT(args.length() == 1);
8049 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008050
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00008051 function->shared()->set_profiler_ticks(0);
8052
lrn@chromium.org34e60782011-09-15 07:25:40 +00008053 // If the function is not compiled ignore the lazy
8054 // recompilation. This can happen if the debugger is activated and
8055 // the function is returned to the not compiled state.
8056 if (!function->shared()->is_compiled()) {
8057 function->ReplaceCode(function->shared()->code());
8058 return function->code();
8059 }
8060
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008061 // If the function is not optimizable or debugger is active continue using the
8062 // code from the full compiler.
8063 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008064 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008065 if (FLAG_trace_opt) {
8066 PrintF("[failed to optimize ");
8067 function->PrintName();
8068 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8069 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008070 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008071 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008072 function->ReplaceCode(function->shared()->code());
8073 return function->code();
8074 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008075 if (JSFunction::CompileOptimized(function,
8076 AstNode::kNoNumber,
8077 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008078 return function->code();
8079 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008080 if (FLAG_trace_opt) {
8081 PrintF("[failed to optimize ");
8082 function->PrintName();
8083 PrintF(": optimized compilation failed]\n");
8084 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008085 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008086 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008087}
8088
8089
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008090class ActivationsFinder : public ThreadVisitor {
8091 public:
8092 explicit ActivationsFinder(JSFunction* function)
8093 : function_(function), has_activations_(false) {}
8094
8095 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8096 if (has_activations_) return;
8097
8098 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8099 JavaScriptFrame* frame = it.frame();
8100 if (frame->is_optimized() && frame->function() == function_) {
8101 has_activations_ = true;
8102 return;
8103 }
8104 }
8105 }
8106
8107 bool has_activations() { return has_activations_; }
8108
8109 private:
8110 JSFunction* function_;
8111 bool has_activations_;
8112};
8113
8114
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008115RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008116 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008117 ASSERT(args.length() == 1);
8118 RUNTIME_ASSERT(args[0]->IsSmi());
8119 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008120 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008121 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8122 ASSERT(isolate->heap()->IsAllocationAllowed());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008123 int jsframes = deoptimizer->jsframe_count();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008124
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008125 deoptimizer->MaterializeHeapNumbers();
8126 delete deoptimizer;
8127
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008128 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008129 JavaScriptFrame* frame = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008130 for (int i = 0; i < jsframes - 1; i++) it.Advance();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008131 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008132
8133 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008134 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008135 Handle<Object> arguments;
8136 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008137 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008138 if (arguments.is_null()) {
8139 // FunctionGetArguments can't throw an exception, so cast away the
8140 // doubt with an assert.
8141 arguments = Handle<Object>(
8142 Accessors::FunctionGetArguments(*function,
8143 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008144 ASSERT(*arguments != isolate->heap()->null_value());
8145 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008146 }
8147 frame->SetExpression(i, *arguments);
8148 }
8149 }
8150
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008151 if (type == Deoptimizer::EAGER) {
8152 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008153 }
8154
8155 // Avoid doing too much work when running with --always-opt and keep
8156 // the optimized code around.
8157 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008158 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008159 }
8160
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008161 // Find other optimized activations of the function.
8162 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008163 while (!it.done()) {
8164 JavaScriptFrame* frame = it.frame();
8165 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008166 has_other_activations = true;
8167 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008168 }
8169 it.Advance();
8170 }
8171
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008172 if (!has_other_activations) {
8173 ActivationsFinder activations_finder(*function);
8174 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8175 has_other_activations = activations_finder.has_activations();
8176 }
8177
8178 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008179 if (FLAG_trace_deopt) {
8180 PrintF("[removing optimized code for: ");
8181 function->PrintName();
8182 PrintF("]\n");
8183 }
8184 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008185 } else {
8186 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008188 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008189}
8190
8191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008192RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008193 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008194 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008195 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008196}
8197
8198
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008199RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008200 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008201 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008202 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008203 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008204
8205 Deoptimizer::DeoptimizeFunction(*function);
8206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008207 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008208}
8209
8210
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008211RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8212#if defined(USE_SIMULATOR)
8213 return isolate->heap()->true_value();
8214#else
8215 return isolate->heap()->false_value();
8216#endif
8217}
8218
8219
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008220RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8221 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008222 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008223 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008224
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008225 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8226 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008227
8228 Code* unoptimized = function->shared()->code();
8229 if (args.length() == 2 &&
8230 unoptimized->kind() == Code::FUNCTION) {
8231 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8232 CHECK(type->IsEqualTo(CStrVector("osr")));
8233 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8234 unoptimized->set_allow_osr_at_loop_nesting_level(
8235 Code::kMaxLoopNestingMarker);
8236 }
8237
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008238 return isolate->heap()->undefined_value();
8239}
8240
8241
lrn@chromium.org1c092762011-05-09 09:42:16 +00008242RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8243 HandleScope scope(isolate);
8244 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008245 // The least significant bit (after untagging) indicates whether the
8246 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008247 if (!V8::UseCrankshaft()) {
8248 return Smi::FromInt(4); // 4 == "never".
8249 }
8250 if (FLAG_always_opt) {
8251 return Smi::FromInt(3); // 3 == "always".
8252 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008253 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008254 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8255 : Smi::FromInt(2); // 2 == "no".
8256}
8257
8258
8259RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8260 HandleScope scope(isolate);
8261 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008262 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008263 return Smi::FromInt(function->shared()->opt_count());
8264}
8265
8266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008267RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008268 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008269 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008270 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008271
8272 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008273 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008274
8275 // We have hit a back edge in an unoptimized frame for a function that was
8276 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008277 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008278 // Keep track of whether we've succeeded in optimizing.
8279 bool succeeded = unoptimized->optimizable();
8280 if (succeeded) {
8281 // If we are trying to do OSR when there are already optimized
8282 // activations of the function, it means (a) the function is directly or
8283 // indirectly recursive and (b) an optimized invocation has been
8284 // deoptimized so that we are currently in an unoptimized activation.
8285 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008286 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008287 while (succeeded && !it.done()) {
8288 JavaScriptFrame* frame = it.frame();
8289 succeeded = !frame->is_optimized() || frame->function() != *function;
8290 it.Advance();
8291 }
8292 }
8293
8294 int ast_id = AstNode::kNoNumber;
8295 if (succeeded) {
8296 // The top JS function is this one, the PC is somewhere in the
8297 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008298 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008299 JavaScriptFrame* frame = it.frame();
8300 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008301 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008302 ASSERT(unoptimized->contains(frame->pc()));
8303
8304 // Use linear search of the unoptimized code's stack check table to find
8305 // the AST id matching the PC.
8306 Address start = unoptimized->instruction_start();
8307 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008308 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008309 uint32_t table_length = Memory::uint32_at(table_cursor);
8310 table_cursor += kIntSize;
8311 for (unsigned i = 0; i < table_length; ++i) {
8312 // Table entries are (AST id, pc offset) pairs.
8313 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8314 if (pc_offset == target_pc_offset) {
8315 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8316 break;
8317 }
8318 table_cursor += 2 * kIntSize;
8319 }
8320 ASSERT(ast_id != AstNode::kNoNumber);
8321 if (FLAG_trace_osr) {
8322 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8323 function->PrintName();
8324 PrintF("]\n");
8325 }
8326
8327 // Try to compile the optimized code. A true return value from
8328 // CompileOptimized means that compilation succeeded, not necessarily
8329 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008330 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008331 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008332 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8333 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008334 if (data->OsrPcOffset()->value() >= 0) {
8335 if (FLAG_trace_osr) {
8336 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008337 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008338 }
8339 ASSERT(data->OsrAstId()->value() == ast_id);
8340 } else {
8341 // We may never generate the desired OSR entry if we emit an
8342 // early deoptimize.
8343 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008344 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008345 } else {
8346 succeeded = false;
8347 }
8348 }
8349
8350 // Revert to the original stack checks in the original unoptimized code.
8351 if (FLAG_trace_osr) {
8352 PrintF("[restoring original stack checks in ");
8353 function->PrintName();
8354 PrintF("]\n");
8355 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008356 Handle<Code> check_code;
8357#ifdef V8_TARGET_ARCH_IA32
8358 if (FLAG_count_based_interrupts) {
8359 InterruptStub interrupt_stub;
8360 check_code = interrupt_stub.GetCode();
8361 } else // NOLINT
8362#endif
8363 { // NOLINT
8364 StackCheckStub check_stub;
8365 check_code = check_stub.GetCode();
8366 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008367 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008368 Deoptimizer::RevertStackCheckCode(*unoptimized,
8369 *check_code,
8370 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008371
8372 // Allow OSR only at nesting level zero again.
8373 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8374
8375 // If the optimization attempt succeeded, return the AST id tagged as a
8376 // smi. This tells the builtin that we need to translate the unoptimized
8377 // frame to an optimized one.
8378 if (succeeded) {
8379 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8380 return Smi::FromInt(ast_id);
8381 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008382 if (function->IsMarkedForLazyRecompilation()) {
8383 function->ReplaceCode(function->shared()->code());
8384 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008385 return Smi::FromInt(-1);
8386 }
8387}
8388
8389
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008390RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8391 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8392 return isolate->heap()->undefined_value();
8393}
8394
8395
danno@chromium.orgc612e022011-11-10 11:38:15 +00008396RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8397 HandleScope scope(isolate);
8398 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008399 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008400 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8401 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008402
8403 // If there are too many arguments, allocate argv via malloc.
8404 const int argv_small_size = 10;
8405 Handle<Object> argv_small_buffer[argv_small_size];
8406 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8407 Handle<Object>* argv = argv_small_buffer;
8408 if (argc > argv_small_size) {
8409 argv = new Handle<Object>[argc];
8410 if (argv == NULL) return isolate->StackOverflow();
8411 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8412 }
8413
8414 for (int i = 0; i < argc; ++i) {
8415 MaybeObject* maybe = args[1 + i];
8416 Object* object;
8417 if (!maybe->To<Object>(&object)) return maybe;
8418 argv[i] = Handle<Object>(object);
8419 }
8420
8421 bool threw;
8422 Handle<JSReceiver> hfun(fun);
8423 Handle<Object> hreceiver(receiver);
8424 Handle<Object> result =
8425 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8426
8427 if (threw) return Failure::Exception();
8428 return *result;
8429}
8430
8431
lrn@chromium.org34e60782011-09-15 07:25:40 +00008432RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8433 HandleScope scope(isolate);
8434 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008435 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008436 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008437 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008438 CONVERT_SMI_ARG_CHECKED(offset, 3);
8439 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008440 ASSERT(offset >= 0);
8441 ASSERT(argc >= 0);
8442
8443 // If there are too many arguments, allocate argv via malloc.
8444 const int argv_small_size = 10;
8445 Handle<Object> argv_small_buffer[argv_small_size];
8446 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8447 Handle<Object>* argv = argv_small_buffer;
8448 if (argc > argv_small_size) {
8449 argv = new Handle<Object>[argc];
8450 if (argv == NULL) return isolate->StackOverflow();
8451 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8452 }
8453
8454 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008455 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008456 }
8457
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008458 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008459 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008460 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008461
8462 if (threw) return Failure::Exception();
8463 return *result;
8464}
8465
8466
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008467RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008468 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008469 ASSERT(args.length() == 1);
8470 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8471 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8472}
8473
8474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008475RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008476 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008477 ASSERT(args.length() == 1);
8478 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8479 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8480}
8481
8482
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008483RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008484 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008485 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008486
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008487 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008488 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008489 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 { MaybeObject* maybe_result =
8491 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008492 if (!maybe_result->ToObject(&result)) return maybe_result;
8493 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008494
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008495 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008496
kasper.lund7276f142008-07-30 08:49:36 +00008497 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008498}
8499
lrn@chromium.org303ada72010-10-27 09:33:13 +00008500
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008501RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8502 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008503 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008504 JSObject* extension_object;
8505 if (args[0]->IsJSObject()) {
8506 extension_object = JSObject::cast(args[0]);
8507 } else {
8508 // Convert the object to a proper JavaScript object.
8509 MaybeObject* maybe_js_object = args[0]->ToObject();
8510 if (!maybe_js_object->To(&extension_object)) {
8511 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8512 HandleScope scope(isolate);
8513 Handle<Object> handle = args.at<Object>(0);
8514 Handle<Object> result =
8515 isolate->factory()->NewTypeError("with_expression",
8516 HandleVector(&handle, 1));
8517 return isolate->Throw(*result);
8518 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008519 return maybe_js_object;
8520 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008521 }
8522 }
8523
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008524 JSFunction* function;
8525 if (args[1]->IsSmi()) {
8526 // A smi sentinel indicates a context nested inside global code rather
8527 // than some function. There is a canonical empty function that can be
8528 // gotten from the global context.
8529 function = isolate->context()->global_context()->closure();
8530 } else {
8531 function = JSFunction::cast(args[1]);
8532 }
8533
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008534 Context* context;
8535 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008536 isolate->heap()->AllocateWithContext(function,
8537 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008538 extension_object);
8539 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008540 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008541 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008542}
8543
8544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008545RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008546 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008547 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008548 String* name = String::cast(args[0]);
8549 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008550 JSFunction* function;
8551 if (args[2]->IsSmi()) {
8552 // A smi sentinel indicates a context nested inside global code rather
8553 // than some function. There is a canonical empty function that can be
8554 // gotten from the global context.
8555 function = isolate->context()->global_context()->closure();
8556 } else {
8557 function = JSFunction::cast(args[2]);
8558 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008559 Context* context;
8560 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008561 isolate->heap()->AllocateCatchContext(function,
8562 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008563 name,
8564 thrown_object);
8565 if (!maybe_context->To(&context)) return maybe_context;
8566 isolate->set_context(context);
8567 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008568}
8569
8570
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008571RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8572 NoHandleAllocation ha;
8573 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008574 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008575 JSFunction* function;
8576 if (args[1]->IsSmi()) {
8577 // A smi sentinel indicates a context nested inside global code rather
8578 // than some function. There is a canonical empty function that can be
8579 // gotten from the global context.
8580 function = isolate->context()->global_context()->closure();
8581 } else {
8582 function = JSFunction::cast(args[1]);
8583 }
8584 Context* context;
8585 MaybeObject* maybe_context =
8586 isolate->heap()->AllocateBlockContext(function,
8587 isolate->context(),
8588 scope_info);
8589 if (!maybe_context->To(&context)) return maybe_context;
8590 isolate->set_context(context);
8591 return context;
8592}
8593
8594
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008595RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008596 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008597 ASSERT(args.length() == 2);
8598
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008599 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8600 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008601
8602 int index;
8603 PropertyAttributes attributes;
8604 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008605 BindingFlags binding_flags;
8606 Handle<Object> holder = context->Lookup(name,
8607 flags,
8608 &index,
8609 &attributes,
8610 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008611
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008612 // If the slot was not found the result is true.
8613 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008614 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008615 }
8616
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008617 // If the slot was found in a context, it should be DONT_DELETE.
8618 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008619 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008620 }
8621
8622 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008623 // the global object, or the subject of a with. Try to delete it
8624 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008625 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008626 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008627}
8628
8629
ager@chromium.orga1645e22009-09-09 19:27:10 +00008630// A mechanism to return a pair of Object pointers in registers (if possible).
8631// How this is achieved is calling convention-dependent.
8632// All currently supported x86 compiles uses calling conventions that are cdecl
8633// variants where a 64-bit value is returned in two 32-bit registers
8634// (edx:eax on ia32, r1:r0 on ARM).
8635// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8636// In Win64 calling convention, a struct of two pointers is returned in memory,
8637// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008638#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008639struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008640 MaybeObject* x;
8641 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008642};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008643
lrn@chromium.org303ada72010-10-27 09:33:13 +00008644static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008645 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008646 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8647 // In Win64 they are assigned to a hidden first argument.
8648 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008649}
8650#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008651typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008652static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008653 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008654 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008655}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008656#endif
8657
8658
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008659static inline MaybeObject* Unhole(Heap* heap,
8660 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008661 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008662 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8663 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008664 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008665}
8666
8667
danno@chromium.org40cb8782011-05-25 07:58:50 +00008668static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8669 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008670 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008671 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008672 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008673 JSFunction* context_extension_function =
8674 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008675 // If the holder isn't a context extension object, we just return it
8676 // as the receiver. This allows arguments objects to be used as
8677 // receivers, but only if they are put in the context scope chain
8678 // explicitly via a with-statement.
8679 Object* constructor = holder->map()->constructor();
8680 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008681 // Fall back to using the global object as the implicit receiver if
8682 // the property turns out to be a local variable allocated in a
8683 // context extension object - introduced via eval. Implicit global
8684 // receivers are indicated with the hole value.
8685 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008686}
8687
8688
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008689static ObjectPair LoadContextSlotHelper(Arguments args,
8690 Isolate* isolate,
8691 bool throw_error) {
8692 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008693 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008694
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008695 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008696 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008697 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008698 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008699 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008700
8701 int index;
8702 PropertyAttributes attributes;
8703 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008704 BindingFlags binding_flags;
8705 Handle<Object> holder = context->Lookup(name,
8706 flags,
8707 &index,
8708 &attributes,
8709 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008710
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008711 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008712 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008713 ASSERT(holder->IsContext());
8714 // If the "property" we were looking for is a local variable, the
8715 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008716 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008717 // Use the hole as the receiver to signal that the receiver is implicit
8718 // and that the global receiver should be used (as distinguished from an
8719 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008720 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008721 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008722 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008723 switch (binding_flags) {
8724 case MUTABLE_CHECK_INITIALIZED:
8725 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8726 if (value->IsTheHole()) {
8727 Handle<Object> reference_error =
8728 isolate->factory()->NewReferenceError("not_defined",
8729 HandleVector(&name, 1));
8730 return MakePair(isolate->Throw(*reference_error), NULL);
8731 }
8732 // FALLTHROUGH
8733 case MUTABLE_IS_INITIALIZED:
8734 case IMMUTABLE_IS_INITIALIZED:
8735 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8736 ASSERT(!value->IsTheHole());
8737 return MakePair(value, *receiver);
8738 case IMMUTABLE_CHECK_INITIALIZED:
8739 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8740 case MISSING_BINDING:
8741 UNREACHABLE();
8742 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008743 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008744 }
8745
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008746 // Otherwise, if the slot was found the holder is a context extension
8747 // object, subject of a with, or a global object. We read the named
8748 // property from it.
8749 if (!holder.is_null()) {
8750 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8751 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008752 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008753 Handle<Object> receiver_handle(object->IsGlobalObject()
8754 ? GlobalObject::cast(*object)->global_receiver()
8755 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008756
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008757 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008758 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008759 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008760 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008761 }
8762
8763 if (throw_error) {
8764 // The property doesn't exist - throw exception.
8765 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008766 isolate->factory()->NewReferenceError("not_defined",
8767 HandleVector(&name, 1));
8768 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008769 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008770 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008771 return MakePair(isolate->heap()->undefined_value(),
8772 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008773 }
8774}
8775
8776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008777RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008778 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008779}
8780
8781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008782RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008783 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008784}
8785
8786
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008787RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008788 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008789 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008790
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008791 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008792 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
8793 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008794 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
8795 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
8796 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008797
8798 int index;
8799 PropertyAttributes attributes;
8800 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008801 BindingFlags binding_flags;
8802 Handle<Object> holder = context->Lookup(name,
8803 flags,
8804 &index,
8805 &attributes,
8806 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008807
8808 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008809 // The property was found in a context slot.
8810 Handle<Context> context = Handle<Context>::cast(holder);
8811 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8812 context->get(index)->IsTheHole()) {
8813 Handle<Object> error =
8814 isolate->factory()->NewReferenceError("not_defined",
8815 HandleVector(&name, 1));
8816 return isolate->Throw(*error);
8817 }
8818 // Ignore if read_only variable.
8819 if ((attributes & READ_ONLY) == 0) {
8820 // Context is a fixed array and set cannot fail.
8821 context->set(index, *value);
8822 } else if (strict_mode == kStrictMode) {
8823 // Setting read only property in strict mode.
8824 Handle<Object> error =
8825 isolate->factory()->NewTypeError("strict_cannot_assign",
8826 HandleVector(&name, 1));
8827 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008828 }
8829 return *value;
8830 }
8831
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008832 // Slow case: The property is not in a context slot. It is either in a
8833 // context extension object, a property of the subject of a with, or a
8834 // property of the global object.
8835 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008836
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008837 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008838 // The property exists on the holder.
8839 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008840 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008841 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008842 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008843
8844 if (strict_mode == kStrictMode) {
8845 // Throw in strict mode (assignment to undefined variable).
8846 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008847 isolate->factory()->NewReferenceError(
8848 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008849 return isolate->Throw(*error);
8850 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008851 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008852 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008853 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008854 }
8855
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008856 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008857 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008858 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008859 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008860 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008861 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008862 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008863 // Setting read only property in strict mode.
8864 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008865 isolate->factory()->NewTypeError(
8866 "strict_cannot_assign", HandleVector(&name, 1));
8867 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008868 }
8869 return *value;
8870}
8871
8872
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008873RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008874 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008875 ASSERT(args.length() == 1);
8876
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008877 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008878}
8879
8880
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008881RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008882 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008883 ASSERT(args.length() == 1);
8884
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008885 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008886}
8887
8888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008889RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008890 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008891 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008892}
8893
8894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008895RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008896 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008897 ASSERT(args.length() == 1);
8898
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008899 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008900 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008901 isolate->factory()->NewReferenceError("not_defined",
8902 HandleVector(&name, 1));
8903 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008904}
8905
8906
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008907RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008908 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008909
8910 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008911 if (isolate->stack_guard()->IsStackOverflow()) {
8912 NoHandleAllocation na;
8913 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008914 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008915
ulan@chromium.org812308e2012-02-29 15:58:45 +00008916 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008917}
8918
8919
yangguo@chromium.org56454712012-02-16 15:33:53 +00008920RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
8921 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008922 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00008923}
8924
8925
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008926static int StackSize() {
8927 int n = 0;
8928 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8929 return n;
8930}
8931
8932
8933static void PrintTransition(Object* result) {
8934 // indentation
8935 { const int nmax = 80;
8936 int n = StackSize();
8937 if (n <= nmax)
8938 PrintF("%4d:%*s", n, n, "");
8939 else
8940 PrintF("%4d:%*s", n, nmax, "...");
8941 }
8942
8943 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008944 JavaScriptFrame::PrintTop(stdout, true, false);
8945 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008946 } else {
8947 // function result
8948 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008949 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008950 PrintF("\n");
8951 }
8952}
8953
8954
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008955RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008956 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008957 NoHandleAllocation ha;
8958 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008959 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008960}
8961
8962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008963RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008964 NoHandleAllocation ha;
8965 PrintTransition(args[0]);
8966 return args[0]; // return TOS
8967}
8968
8969
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008970RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008971 NoHandleAllocation ha;
8972 ASSERT(args.length() == 1);
8973
8974#ifdef DEBUG
8975 if (args[0]->IsString()) {
8976 // If we have a string, assume it's a code "marker"
8977 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008978 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008979 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008980 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8981 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008982 } else {
8983 PrintF("DebugPrint: ");
8984 }
8985 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008986 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008987 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008988 HeapObject::cast(args[0])->map()->Print();
8989 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008990#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008991 // ShortPrint is available in release mode. Print is not.
8992 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008993#endif
8994 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008995 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008996
8997 return args[0]; // return TOS
8998}
8999
9000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009001RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009002 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009003 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009004 isolate->PrintStack();
9005 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009006}
9007
9008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009009RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009010 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009011 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009012
9013 // According to ECMA-262, section 15.9.1, page 117, the precision of
9014 // the number in a Date object representing a particular instant in
9015 // time is milliseconds. Therefore, we floor the result of getting
9016 // the OS time.
9017 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009018 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019}
9020
9021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009022RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009023 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009024 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009025
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009026 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009027 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009028
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009029 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009030
9031 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009032 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009033 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009034 RUNTIME_ASSERT(output->HasFastElements());
9035
9036 AssertNoAllocation no_allocation;
9037
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009038 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009039 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9040 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009041 String::FlatContent str_content = str->GetFlatContent();
9042 if (str_content.IsAscii()) {
9043 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009044 output_array,
9045 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009046 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009047 ASSERT(str_content.IsTwoByte());
9048 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009049 output_array,
9050 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009051 }
9052
9053 if (result) {
9054 return *output;
9055 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009056 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009057 }
9058}
9059
9060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009061RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009062 NoHandleAllocation ha;
9063 ASSERT(args.length() == 1);
9064
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009065 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009066 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9067 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009068 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009069}
9070
9071
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009072RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009073 NoHandleAllocation ha;
9074 ASSERT(args.length() == 1);
9075
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009076 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009077 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9078
9079 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009080}
9081
9082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009083RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009084 ASSERT(args.length() == 1);
9085 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009086 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009087 return JSGlobalObject::cast(global)->global_receiver();
9088}
9089
9090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009091RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009092 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009093 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009094 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009095
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009096 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009097 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009098 Handle<Object> result;
9099 if (source->IsSeqAsciiString()) {
9100 result = JsonParser<true>::Parse(source);
9101 } else {
9102 result = JsonParser<false>::Parse(source);
9103 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009104 if (result.is_null()) {
9105 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009106 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009107 return Failure::Exception();
9108 }
9109 return *result;
9110}
9111
9112
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009113bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9114 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009115 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9116 // Check with callback if set.
9117 AllowCodeGenerationFromStringsCallback callback =
9118 isolate->allow_code_gen_callback();
9119 if (callback == NULL) {
9120 // No callback set and code generation disallowed.
9121 return false;
9122 } else {
9123 // Callback set. Let it decide if code generation is allowed.
9124 VMState state(isolate, EXTERNAL);
9125 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009126 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009127}
9128
9129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009130RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009131 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009132 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009133 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009134
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009135 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009136 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009137
9138 // Check if global context allows code generation from
9139 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009140 if (context->allow_code_gen_from_strings()->IsFalse() &&
9141 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009142 return isolate->Throw(*isolate->factory()->NewError(
9143 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9144 }
9145
9146 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009147 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009148 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009149 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009150 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009151 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9152 context,
9153 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009154 return *fun;
9155}
9156
9157
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009158static ObjectPair CompileGlobalEval(Isolate* isolate,
9159 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009160 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009161 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009162 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009163 Handle<Context> context = Handle<Context>(isolate->context());
9164 Handle<Context> global_context = Handle<Context>(context->global_context());
9165
9166 // Check if global context allows code generation from
9167 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009168 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9169 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009170 isolate->Throw(*isolate->factory()->NewError(
9171 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9172 return MakePair(Failure::Exception(), NULL);
9173 }
9174
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009175 // Deal with a normal eval call with a string argument. Compile it
9176 // and return the compiled function bound in the local context.
9177 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9178 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009179 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009180 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009181 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009182 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009183 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009184 Handle<JSFunction> compiled =
9185 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009186 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009187 return MakePair(*compiled, *receiver);
9188}
9189
9190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009191RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009192 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009193
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009194 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009195 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009196
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009197 // If "eval" didn't refer to the original GlobalEval, it's not a
9198 // direct call to eval.
9199 // (And even if it is, but the first argument isn't a string, just let
9200 // execution default to an indirect call to eval, which will also return
9201 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009202 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009203 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009204 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009205 }
9206
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009207 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009208 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009209 return CompileGlobalEval(isolate,
9210 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009211 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009212 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009213 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009214}
9215
9216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009217RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009218 // This utility adjusts the property attributes for newly created Function
9219 // object ("new Function(...)") by changing the map.
9220 // All it does is changing the prototype property to enumerable
9221 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009222 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009223 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009224 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009225
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009226 Handle<Map> map = func->shared()->is_classic_mode()
9227 ? isolate->function_instance_map()
9228 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009229
9230 ASSERT(func->map()->instance_type() == map->instance_type());
9231 ASSERT(func->map()->instance_size() == map->instance_size());
9232 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009233 return *func;
9234}
9235
9236
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009237RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009238 // Allocate a block of memory in NewSpace (filled with a filler).
9239 // Use as fallback for allocation in generated code when NewSpace
9240 // is full.
9241 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009242 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009243 int size = size_smi->value();
9244 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9245 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009246 Heap* heap = isolate->heap();
9247 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009248 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009249 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009250 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009251 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009252 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009253 }
9254 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009255 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009256}
9257
9258
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009259// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009260// array. Returns true if the element was pushed on the stack and
9261// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009262RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009263 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009264 CONVERT_ARG_CHECKED(JSArray, array, 0);
9265 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009266 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009267 int length = Smi::cast(array->length())->value();
9268 FixedArray* elements = FixedArray::cast(array->elements());
9269 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009270 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009271 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009272 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009273 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009274 { MaybeObject* maybe_obj =
9275 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009276 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9277 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009278 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009279}
9280
9281
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009282/**
9283 * A simple visitor visits every element of Array's.
9284 * The backend storage can be a fixed array for fast elements case,
9285 * or a dictionary for sparse array. Since Dictionary is a subtype
9286 * of FixedArray, the class can be used by both fast and slow cases.
9287 * The second parameter of the constructor, fast_elements, specifies
9288 * whether the storage is a FixedArray or Dictionary.
9289 *
9290 * An index limit is used to deal with the situation that a result array
9291 * length overflows 32-bit non-negative integer.
9292 */
9293class ArrayConcatVisitor {
9294 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009295 ArrayConcatVisitor(Isolate* isolate,
9296 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009297 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009298 isolate_(isolate),
9299 storage_(Handle<FixedArray>::cast(
9300 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009301 index_offset_(0u),
9302 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009303
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009304 ~ArrayConcatVisitor() {
9305 clear_storage();
9306 }
9307
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009308 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009309 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009310 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009311
9312 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009313 if (index < static_cast<uint32_t>(storage_->length())) {
9314 storage_->set(index, *elm);
9315 return;
9316 }
9317 // Our initial estimate of length was foiled, possibly by
9318 // getters on the arrays increasing the length of later arrays
9319 // during iteration.
9320 // This shouldn't happen in anything but pathological cases.
9321 SetDictionaryMode(index);
9322 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009323 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009324 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009325 Handle<SeededNumberDictionary> dict(
9326 SeededNumberDictionary::cast(*storage_));
9327 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009328 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009329 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009330 // Dictionary needed to grow.
9331 clear_storage();
9332 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009333 }
9334}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009335
9336 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009337 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9338 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009339 } else {
9340 index_offset_ += delta;
9341 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009342 }
9343
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009344 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009345 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009346 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009347 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009348 Handle<Map> map;
9349 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009350 map = isolate_->factory()->GetElementsTransitionMap(array,
9351 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009352 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009353 map = isolate_->factory()->GetElementsTransitionMap(array,
9354 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009355 }
9356 array->set_map(*map);
9357 array->set_length(*length);
9358 array->set_elements(*storage_);
9359 return array;
9360 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009361
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009362 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009363 // Convert storage to dictionary mode.
9364 void SetDictionaryMode(uint32_t index) {
9365 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009366 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009367 Handle<SeededNumberDictionary> slow_storage(
9368 isolate_->factory()->NewSeededNumberDictionary(
9369 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009370 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9371 for (uint32_t i = 0; i < current_length; i++) {
9372 HandleScope loop_scope;
9373 Handle<Object> element(current_storage->get(i));
9374 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009375 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009376 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009377 if (!new_storage.is_identical_to(slow_storage)) {
9378 slow_storage = loop_scope.CloseAndEscape(new_storage);
9379 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009380 }
9381 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009382 clear_storage();
9383 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009384 fast_elements_ = false;
9385 }
9386
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009387 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009388 isolate_->global_handles()->Destroy(
9389 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009390 }
9391
9392 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009393 storage_ = Handle<FixedArray>::cast(
9394 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009395 }
9396
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009397 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009398 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009399 // Index after last seen index. Always less than or equal to
9400 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009401 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009402 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009403};
9404
9405
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009406static uint32_t EstimateElementCount(Handle<JSArray> array) {
9407 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9408 int element_count = 0;
9409 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009410 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009411 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009412 // Fast elements can't have lengths that are not representable by
9413 // a 32-bit signed integer.
9414 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9415 int fast_length = static_cast<int>(length);
9416 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9417 for (int i = 0; i < fast_length; i++) {
9418 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009419 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009420 break;
9421 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009422 case FAST_DOUBLE_ELEMENTS:
9423 // TODO(1810): Decide if it's worthwhile to implement this.
9424 UNREACHABLE();
9425 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009426 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009427 Handle<SeededNumberDictionary> dictionary(
9428 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009429 int capacity = dictionary->Capacity();
9430 for (int i = 0; i < capacity; i++) {
9431 Handle<Object> key(dictionary->KeyAt(i));
9432 if (dictionary->IsKey(*key)) {
9433 element_count++;
9434 }
9435 }
9436 break;
9437 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009438 case NON_STRICT_ARGUMENTS_ELEMENTS:
9439 case EXTERNAL_BYTE_ELEMENTS:
9440 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9441 case EXTERNAL_SHORT_ELEMENTS:
9442 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9443 case EXTERNAL_INT_ELEMENTS:
9444 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9445 case EXTERNAL_FLOAT_ELEMENTS:
9446 case EXTERNAL_DOUBLE_ELEMENTS:
9447 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009448 // External arrays are always dense.
9449 return length;
9450 }
9451 // As an estimate, we assume that the prototype doesn't contain any
9452 // inherited elements.
9453 return element_count;
9454}
9455
9456
9457
9458template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009459static void IterateExternalArrayElements(Isolate* isolate,
9460 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009461 bool elements_are_ints,
9462 bool elements_are_guaranteed_smis,
9463 ArrayConcatVisitor* visitor) {
9464 Handle<ExternalArrayClass> array(
9465 ExternalArrayClass::cast(receiver->elements()));
9466 uint32_t len = static_cast<uint32_t>(array->length());
9467
9468 ASSERT(visitor != NULL);
9469 if (elements_are_ints) {
9470 if (elements_are_guaranteed_smis) {
9471 for (uint32_t j = 0; j < len; j++) {
9472 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009473 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009474 visitor->visit(j, e);
9475 }
9476 } else {
9477 for (uint32_t j = 0; j < len; j++) {
9478 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009479 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009480 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9481 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9482 visitor->visit(j, e);
9483 } else {
9484 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009485 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009486 visitor->visit(j, e);
9487 }
9488 }
9489 }
9490 } else {
9491 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009492 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009493 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009494 visitor->visit(j, e);
9495 }
9496 }
9497}
9498
9499
9500// Used for sorting indices in a List<uint32_t>.
9501static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9502 uint32_t a = *ap;
9503 uint32_t b = *bp;
9504 return (a == b) ? 0 : (a < b) ? -1 : 1;
9505}
9506
9507
9508static void CollectElementIndices(Handle<JSObject> object,
9509 uint32_t range,
9510 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009511 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009512 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009513 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009514 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009515 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9516 uint32_t length = static_cast<uint32_t>(elements->length());
9517 if (range < length) length = range;
9518 for (uint32_t i = 0; i < length; i++) {
9519 if (!elements->get(i)->IsTheHole()) {
9520 indices->Add(i);
9521 }
9522 }
9523 break;
9524 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009525 case FAST_DOUBLE_ELEMENTS: {
9526 // TODO(1810): Decide if it's worthwhile to implement this.
9527 UNREACHABLE();
9528 break;
9529 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009530 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009531 Handle<SeededNumberDictionary> dict(
9532 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009533 uint32_t capacity = dict->Capacity();
9534 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009535 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009536 Handle<Object> k(dict->KeyAt(j));
9537 if (dict->IsKey(*k)) {
9538 ASSERT(k->IsNumber());
9539 uint32_t index = static_cast<uint32_t>(k->Number());
9540 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009541 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009542 }
9543 }
9544 }
9545 break;
9546 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009547 default: {
9548 int dense_elements_length;
9549 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009550 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009551 dense_elements_length =
9552 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009553 break;
9554 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009555 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009556 dense_elements_length =
9557 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009558 break;
9559 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009560 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009561 dense_elements_length =
9562 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009563 break;
9564 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009565 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009566 dense_elements_length =
9567 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009568 break;
9569 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009570 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009571 dense_elements_length =
9572 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009573 break;
9574 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009575 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009576 dense_elements_length =
9577 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009578 break;
9579 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009580 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009581 dense_elements_length =
9582 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009583 break;
9584 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009585 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009586 dense_elements_length =
9587 ExternalFloatArray::cast(object->elements())->length();
9588 break;
9589 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009590 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009591 dense_elements_length =
9592 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009593 break;
9594 }
9595 default:
9596 UNREACHABLE();
9597 dense_elements_length = 0;
9598 break;
9599 }
9600 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9601 if (range <= length) {
9602 length = range;
9603 // We will add all indices, so we might as well clear it first
9604 // and avoid duplicates.
9605 indices->Clear();
9606 }
9607 for (uint32_t i = 0; i < length; i++) {
9608 indices->Add(i);
9609 }
9610 if (length == range) return; // All indices accounted for already.
9611 break;
9612 }
9613 }
9614
9615 Handle<Object> prototype(object->GetPrototype());
9616 if (prototype->IsJSObject()) {
9617 // The prototype will usually have no inherited element indices,
9618 // but we have to check.
9619 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9620 }
9621}
9622
9623
9624/**
9625 * A helper function that visits elements of a JSArray in numerical
9626 * order.
9627 *
9628 * The visitor argument called for each existing element in the array
9629 * with the element index and the element's value.
9630 * Afterwards it increments the base-index of the visitor by the array
9631 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009632 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009633 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009634static bool IterateElements(Isolate* isolate,
9635 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009636 ArrayConcatVisitor* visitor) {
9637 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9638 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009639 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009640 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009641 // Run through the elements FixedArray and use HasElement and GetElement
9642 // to check the prototype for missing elements.
9643 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9644 int fast_length = static_cast<int>(length);
9645 ASSERT(fast_length <= elements->length());
9646 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009647 HandleScope loop_scope(isolate);
9648 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009649 if (!element_value->IsTheHole()) {
9650 visitor->visit(j, element_value);
9651 } else if (receiver->HasElement(j)) {
9652 // Call GetElement on receiver, not its prototype, or getters won't
9653 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009654 element_value = Object::GetElement(receiver, j);
9655 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009656 visitor->visit(j, element_value);
9657 }
9658 }
9659 break;
9660 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009661 case FAST_DOUBLE_ELEMENTS: {
9662 // TODO(1810): Decide if it's worthwhile to implement this.
9663 UNREACHABLE();
9664 break;
9665 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009666 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009667 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009668 List<uint32_t> indices(dict->Capacity() / 2);
9669 // Collect all indices in the object and the prototypes less
9670 // than length. This might introduce duplicates in the indices list.
9671 CollectElementIndices(receiver, length, &indices);
9672 indices.Sort(&compareUInt32);
9673 int j = 0;
9674 int n = indices.length();
9675 while (j < n) {
9676 HandleScope loop_scope;
9677 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009678 Handle<Object> element = Object::GetElement(receiver, index);
9679 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009680 visitor->visit(index, element);
9681 // Skip to next different index (i.e., omit duplicates).
9682 do {
9683 j++;
9684 } while (j < n && indices[j] == index);
9685 }
9686 break;
9687 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009688 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009689 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9690 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009691 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009692 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009693 visitor->visit(j, e);
9694 }
9695 break;
9696 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009697 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009698 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009699 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009700 break;
9701 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009702 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009703 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009704 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009705 break;
9706 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009707 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009708 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009709 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009710 break;
9711 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009712 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009713 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009714 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009715 break;
9716 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009717 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009718 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009719 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009720 break;
9721 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009722 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009723 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009724 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009725 break;
9726 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009727 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009728 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009729 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009730 break;
9731 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009732 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009733 IterateExternalArrayElements<ExternalDoubleArray, double>(
9734 isolate, receiver, false, false, visitor);
9735 break;
9736 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009737 default:
9738 UNREACHABLE();
9739 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009740 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009741 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009742 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009743}
9744
9745
9746/**
9747 * Array::concat implementation.
9748 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009749 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009750 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009751 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009752RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009753 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009754 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009755
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009756 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009757 int argument_count = static_cast<int>(arguments->length()->Number());
9758 RUNTIME_ASSERT(arguments->HasFastElements());
9759 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009760
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009761 // Pass 1: estimate the length and number of elements of the result.
9762 // The actual length can be larger if any of the arguments have getters
9763 // that mutate other arguments (but will otherwise be precise).
9764 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009765
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009766 uint32_t estimate_result_length = 0;
9767 uint32_t estimate_nof_elements = 0;
9768 {
9769 for (int i = 0; i < argument_count; i++) {
9770 HandleScope loop_scope;
9771 Handle<Object> obj(elements->get(i));
9772 uint32_t length_estimate;
9773 uint32_t element_estimate;
9774 if (obj->IsJSArray()) {
9775 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009776 // TODO(1810): Find out if it's worthwhile to properly support
9777 // arbitrary ElementsKinds. For now, pessimistically transition to
9778 // FAST_ELEMENTS.
9779 if (array->HasFastDoubleElements()) {
9780 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009781 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009782 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009783 length_estimate =
9784 static_cast<uint32_t>(array->length()->Number());
9785 element_estimate =
9786 EstimateElementCount(array);
9787 } else {
9788 length_estimate = 1;
9789 element_estimate = 1;
9790 }
9791 // Avoid overflows by capping at kMaxElementCount.
9792 if (JSObject::kMaxElementCount - estimate_result_length <
9793 length_estimate) {
9794 estimate_result_length = JSObject::kMaxElementCount;
9795 } else {
9796 estimate_result_length += length_estimate;
9797 }
9798 if (JSObject::kMaxElementCount - estimate_nof_elements <
9799 element_estimate) {
9800 estimate_nof_elements = JSObject::kMaxElementCount;
9801 } else {
9802 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009803 }
9804 }
9805 }
9806
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009807 // If estimated number of elements is more than half of length, a
9808 // fixed array (fast case) is more time and space-efficient than a
9809 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009810 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009811
9812 Handle<FixedArray> storage;
9813 if (fast_case) {
9814 // The backing storage array must have non-existing elements to
9815 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009816 storage = isolate->factory()->NewFixedArrayWithHoles(
9817 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009818 } else {
9819 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9820 uint32_t at_least_space_for = estimate_nof_elements +
9821 (estimate_nof_elements >> 2);
9822 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009823 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009824 }
9825
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009826 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009827
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009828 for (int i = 0; i < argument_count; i++) {
9829 Handle<Object> obj(elements->get(i));
9830 if (obj->IsJSArray()) {
9831 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009832 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009833 return Failure::Exception();
9834 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009835 } else {
9836 visitor.visit(0, obj);
9837 visitor.increase_index_offset(1);
9838 }
9839 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009840
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009841 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009842}
9843
9844
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009845// This will not allocate (flatten the string), but it may run
9846// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009847RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009848 NoHandleAllocation ha;
9849 ASSERT(args.length() == 1);
9850
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009851 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009852 StringInputBuffer buffer(string);
9853 while (buffer.has_more()) {
9854 uint16_t character = buffer.GetNext();
9855 PrintF("%c", character);
9856 }
9857 return string;
9858}
9859
ager@chromium.org5ec48922009-05-05 07:25:34 +00009860// Moves all own elements of an object, that are below a limit, to positions
9861// starting at zero. All undefined values are placed after non-undefined values,
9862// and are followed by non-existing element. Does not change the length
9863// property.
9864// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009865RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009866 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009867 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009868 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9869 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009870}
9871
9872
9873// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009874RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009875 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009876 CONVERT_ARG_CHECKED(JSArray, from, 0);
9877 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009878 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009879 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009880 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009881 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9882 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009883 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009884 } else if (new_elements->map() ==
9885 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009886 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009887 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009888 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009889 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009890 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009891 Object* new_map;
9892 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009893 to->set_map(Map::cast(new_map));
9894 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009895 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009896 Object* obj;
9897 { MaybeObject* maybe_obj = from->ResetElements();
9898 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9899 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009900 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009901 return to;
9902}
9903
9904
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009905// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009906RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009907 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009908 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009909 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009910 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009911 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
9912 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009913 } else if (object->IsJSArray()) {
9914 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009915 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009916 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009917 }
9918}
9919
9920
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009921RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009922 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009923
9924 ASSERT_EQ(3, args.length());
9925
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009926 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009927 Handle<Object> key1 = args.at<Object>(1);
9928 Handle<Object> key2 = args.at<Object>(2);
9929
9930 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009931 if (!key1->ToArrayIndex(&index1)
9932 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009933 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009934 }
9935
ager@chromium.orgac091b72010-05-05 07:34:42 +00009936 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009937 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009938 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009939 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009940 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009941
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009942 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009943 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009944 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009945 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009946
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009947 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009948}
9949
9950
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009951// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009952// might have elements. Can either return keys (positive integers) or
9953// intervals (pair of a negative integer (-start-1) followed by a
9954// positive (length)) or undefined values.
9955// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009956RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009957 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009958 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009959 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009960 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009961 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009962 // Create an array and get all the keys into it, then remove all the
9963 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009964 bool threw = false;
9965 Handle<FixedArray> keys =
9966 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
9967 if (threw) return Failure::Exception();
9968
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009969 int keys_length = keys->length();
9970 for (int i = 0; i < keys_length; i++) {
9971 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009972 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009973 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009974 // Zap invalid keys.
9975 keys->set_undefined(i);
9976 }
9977 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009978 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009979 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009980 ASSERT(array->HasFastElements() ||
9981 array->HasFastSmiOnlyElements() ||
9982 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009983 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009984 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009985 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009986 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009987 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009988 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009989 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009990 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009991 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009992 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009993 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009994 }
9995}
9996
9997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009998RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009999 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010000 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10001 CONVERT_ARG_CHECKED(String, name, 1);
10002 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010003 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10004 return obj->LookupAccessor(name, component);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010005}
10006
10007
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010008#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010009RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010010 ASSERT(args.length() == 0);
10011 return Execution::DebugBreakHelper();
10012}
10013
10014
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010015// Helper functions for wrapping and unwrapping stack frame ids.
10016static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010017 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010018 return Smi::FromInt(id >> 2);
10019}
10020
10021
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010022static StackFrame::Id UnwrapFrameId(int wrapped) {
10023 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010024}
10025
10026
10027// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010028// args[0]: debug event listener function to set or null or undefined for
10029// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010030// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010031RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010032 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010033 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10034 args[0]->IsUndefined() ||
10035 args[0]->IsNull());
10036 Handle<Object> callback = args.at<Object>(0);
10037 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010038 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010039
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010040 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010041}
10042
10043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010044RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010045 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010046 isolate->stack_guard()->DebugBreak();
10047 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010048}
10049
10050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010051static MaybeObject* DebugLookupResultValue(Heap* heap,
10052 Object* receiver,
10053 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010054 LookupResult* result,
10055 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010056 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010057 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010058 case NORMAL:
10059 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010060 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010061 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010062 }
10063 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010064 case FIELD:
10065 value =
10066 JSObject::cast(
10067 result->holder())->FastPropertyAt(result->GetFieldIndex());
10068 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010069 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010070 }
10071 return value;
10072 case CONSTANT_FUNCTION:
10073 return result->GetConstantFunction();
10074 case CALLBACKS: {
10075 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010076 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010077 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10078 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010079 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010080 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010081 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010082 maybe_value = heap->isolate()->pending_exception();
10083 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010084 if (caught_exception != NULL) {
10085 *caught_exception = true;
10086 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010087 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010088 }
10089 return value;
10090 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010091 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010092 }
10093 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010094 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010095 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010096 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010097 case CONSTANT_TRANSITION:
10098 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010099 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010100 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010101 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010102 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010104 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010105 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010106}
10107
10108
ager@chromium.org32912102009-01-16 10:38:43 +000010109// Get debugger related details for an object property.
10110// args[0]: object holding property
10111// args[1]: name of the property
10112//
10113// The array returned contains the following information:
10114// 0: Property value
10115// 1: Property details
10116// 2: Property value is exception
10117// 3: Getter function if defined
10118// 4: Setter function if defined
10119// Items 2-4 are only filled if the property has either a getter or a setter
10120// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010121RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010122 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010123
10124 ASSERT(args.length() == 2);
10125
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010126 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10127 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010128
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010129 // Make sure to set the current context to the context before the debugger was
10130 // entered (if the debugger is entered). The reason for switching context here
10131 // is that for some property lookups (accessors and interceptors) callbacks
10132 // into the embedding application can occour, and the embedding application
10133 // could have the assumption that its own global context is the current
10134 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010135 SaveContext save(isolate);
10136 if (isolate->debug()->InDebugger()) {
10137 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010138 }
10139
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010140 // Skip the global proxy as it has no properties and always delegates to the
10141 // real global object.
10142 if (obj->IsJSGlobalProxy()) {
10143 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10144 }
10145
10146
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010147 // Check if the name is trivially convertible to an index and get the element
10148 // if so.
10149 uint32_t index;
10150 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010151 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010152 Object* element_or_char;
10153 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010154 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010155 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10156 return maybe_element_or_char;
10157 }
10158 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010159 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010160 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010161 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010162 }
10163
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010164 // Find the number of objects making up this.
10165 int length = LocalPrototypeChainLength(*obj);
10166
10167 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010168 Handle<JSObject> jsproto = obj;
10169 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010170 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010171 jsproto->LocalLookup(*name, &result);
10172 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010173 // LookupResult is not GC safe as it holds raw object pointers.
10174 // GC can happen later in this code so put the required fields into
10175 // local variables using handles when required for later use.
10176 PropertyType result_type = result.type();
10177 Handle<Object> result_callback_obj;
10178 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010179 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10180 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010181 }
10182 Smi* property_details = result.GetPropertyDetails().AsSmi();
10183 // DebugLookupResultValue can cause GC so details from LookupResult needs
10184 // to be copied to handles before this.
10185 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010186 Object* raw_value;
10187 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010188 DebugLookupResultValue(isolate->heap(), *obj, *name,
10189 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010190 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10191 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010192 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010193
10194 // If the callback object is a fixed array then it contains JavaScript
10195 // getter and/or setter.
10196 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010197 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010198 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010199 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010200 details->set(0, *value);
10201 details->set(1, property_details);
10202 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010203 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010204 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010205 details->set(3, accessors->SafeGet(ACCESSOR_GETTER));
10206 details->set(4, accessors->SafeGet(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010207 }
10208
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010209 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010210 }
10211 if (i < length - 1) {
10212 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10213 }
10214 }
10215
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010216 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010217}
10218
10219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010220RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010221 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010222
10223 ASSERT(args.length() == 2);
10224
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010225 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10226 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010227
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010228 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010229 obj->Lookup(*name, &result);
10230 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010231 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010232 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010233 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010234}
10235
10236
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010237// Return the property type calculated from the property details.
10238// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010239RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010241 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10242 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010243}
10244
10245
10246// Return the property attribute calculated from the property details.
10247// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010248RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010249 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010250 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10251 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010252}
10253
10254
10255// Return the property insertion index calculated from the property details.
10256// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010257RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010258 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010259 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10260 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010261}
10262
10263
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264// Return property value from named interceptor.
10265// args[0]: object
10266// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010267RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010268 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010269 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010270 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010271 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010272 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010273
10274 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010275 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010276}
10277
10278
10279// Return element value from indexed interceptor.
10280// args[0]: object
10281// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010282RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010283 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010284 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010285 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10287 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10288
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010289 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010290}
10291
10292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010293RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294 ASSERT(args.length() >= 1);
10295 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010296 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010297 if (isolate->debug()->break_id() == 0 ||
10298 break_id != isolate->debug()->break_id()) {
10299 return isolate->Throw(
10300 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010301 }
10302
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010303 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010304}
10305
10306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010307RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010308 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309 ASSERT(args.length() == 1);
10310
10311 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010312 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010313 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10314 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010315 if (!maybe_result->ToObject(&result)) return maybe_result;
10316 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010317
10318 // Count all frames which are relevant to debugging stack trace.
10319 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010320 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010321 if (id == StackFrame::NO_ID) {
10322 // If there is no JavaScript stack frame count is 0.
10323 return Smi::FromInt(0);
10324 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010325
10326 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10327 n += it.frame()->GetInlineCount();
10328 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010329 return Smi::FromInt(n);
10330}
10331
10332
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010333class FrameInspector {
10334 public:
10335 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010336 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010337 Isolate* isolate)
10338 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10339 // Calculate the deoptimized frame.
10340 if (frame->is_optimized()) {
10341 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010342 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010343 }
10344 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010345 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010346 is_optimized_ = frame_->is_optimized();
10347 }
10348
10349 ~FrameInspector() {
10350 // Get rid of the calculated deoptimized frame if any.
10351 if (deoptimized_frame_ != NULL) {
10352 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10353 isolate_);
10354 }
10355 }
10356
10357 int GetParametersCount() {
10358 return is_optimized_
10359 ? deoptimized_frame_->parameters_count()
10360 : frame_->ComputeParametersCount();
10361 }
10362 int expression_count() { return deoptimized_frame_->expression_count(); }
10363 Object* GetFunction() {
10364 return is_optimized_
10365 ? deoptimized_frame_->GetFunction()
10366 : frame_->function();
10367 }
10368 Object* GetParameter(int index) {
10369 return is_optimized_
10370 ? deoptimized_frame_->GetParameter(index)
10371 : frame_->GetParameter(index);
10372 }
10373 Object* GetExpression(int index) {
10374 return is_optimized_
10375 ? deoptimized_frame_->GetExpression(index)
10376 : frame_->GetExpression(index);
10377 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010378 int GetSourcePosition() {
10379 return is_optimized_
10380 ? deoptimized_frame_->GetSourcePosition()
10381 : frame_->LookupCode()->SourcePosition(frame_->pc());
10382 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010383 bool IsConstructor() {
10384 return is_optimized_ && !is_bottommost_
10385 ? deoptimized_frame_->HasConstructStub()
10386 : frame_->IsConstructor();
10387 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010388
10389 // To inspect all the provided arguments the frame might need to be
10390 // replaced with the arguments frame.
10391 void SetArgumentsFrame(JavaScriptFrame* frame) {
10392 ASSERT(has_adapted_arguments_);
10393 frame_ = frame;
10394 is_optimized_ = frame_->is_optimized();
10395 ASSERT(!is_optimized_);
10396 }
10397
10398 private:
10399 JavaScriptFrame* frame_;
10400 DeoptimizedFrameInfo* deoptimized_frame_;
10401 Isolate* isolate_;
10402 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010403 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010404 bool has_adapted_arguments_;
10405
10406 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10407};
10408
10409
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010410static const int kFrameDetailsFrameIdIndex = 0;
10411static const int kFrameDetailsReceiverIndex = 1;
10412static const int kFrameDetailsFunctionIndex = 2;
10413static const int kFrameDetailsArgumentCountIndex = 3;
10414static const int kFrameDetailsLocalCountIndex = 4;
10415static const int kFrameDetailsSourcePositionIndex = 5;
10416static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010417static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010418static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010419static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010420
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010421
10422static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10423 JavaScriptFrame* frame) {
10424 SaveContext* save = isolate->save_context();
10425 while (save != NULL && !save->IsBelowFrame(frame)) {
10426 save = save->prev();
10427 }
10428 ASSERT(save != NULL);
10429 return save;
10430}
10431
10432
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010433// Return an array with frame details
10434// args[0]: number: break id
10435// args[1]: number: frame index
10436//
10437// The array returned contains the following information:
10438// 0: Frame id
10439// 1: Receiver
10440// 2: Function
10441// 3: Argument count
10442// 4: Local count
10443// 5: Source position
10444// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010445// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010446// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010447// Arguments name, value
10448// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010449// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010450RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010451 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010452 ASSERT(args.length() == 2);
10453
10454 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010455 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010456 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10457 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010458 if (!maybe_check->ToObject(&check)) return maybe_check;
10459 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010460 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010461 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010462
10463 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010464 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010465 if (id == StackFrame::NO_ID) {
10466 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010467 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010468 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010469
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010470 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010471 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010472 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010473 if (index < count + it.frame()->GetInlineCount()) break;
10474 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010475 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010476 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010477
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010478 bool is_optimized = it.frame()->is_optimized();
10479
10480 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10481 if (is_optimized) {
10482 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010483 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010484 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010485 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010486
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010487 // Traverse the saved contexts chain to find the active context for the
10488 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010489 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010490
10491 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010492 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010493
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010494 // Find source position in unoptimized code.
10495 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010496
ulan@chromium.org967e2702012-02-28 09:49:15 +000010497 // Check for constructor frame.
10498 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010499
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010500 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010501 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010502 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010503 Handle<ScopeInfo> scope_info(shared->scope_info());
10504 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010505
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010506 // Get the locals names and values into a temporary array.
10507 //
10508 // TODO(1240907): Hide compiler-introduced stack variables
10509 // (e.g. .result)? For users of the debugger, they will probably be
10510 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010511 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010512 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010513
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010514 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010515 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010516 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010517 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010518 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010519 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010520 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010521 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010522 // Get the context containing declarations.
10523 Handle<Context> context(
10524 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010525 for (; i < scope_info->LocalCount(); ++i) {
10526 Handle<String> name(scope_info->LocalName(i));
10527 VariableMode mode;
10528 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010529 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010530 locals->set(i * 2 + 1, context->get(
10531 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010532 }
10533 }
10534
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010535 // Check whether this frame is positioned at return. If not top
10536 // frame or if the frame is optimized it cannot be at a return.
10537 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010538 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010539 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010540 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010541
10542 // If positioned just before return find the value to be returned and add it
10543 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010544 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010545 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010546 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010547 Address internal_frame_sp = NULL;
10548 while (!it2.done()) {
10549 if (it2.frame()->is_internal()) {
10550 internal_frame_sp = it2.frame()->sp();
10551 } else {
10552 if (it2.frame()->is_java_script()) {
10553 if (it2.frame()->id() == it.frame()->id()) {
10554 // The internal frame just before the JavaScript frame contains the
10555 // value to return on top. A debug break at return will create an
10556 // internal frame to store the return value (eax/rax/r0) before
10557 // entering the debug break exit frame.
10558 if (internal_frame_sp != NULL) {
10559 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010560 Handle<Object>(Memory::Object_at(internal_frame_sp),
10561 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010562 break;
10563 }
10564 }
10565 }
10566
10567 // Indicate that the previous frame was not an internal frame.
10568 internal_frame_sp = NULL;
10569 }
10570 it2.Advance();
10571 }
10572 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010573
10574 // Now advance to the arguments adapter frame (if any). It contains all
10575 // the provided parameters whereas the function frame always have the number
10576 // of arguments matching the functions parameters. The rest of the
10577 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010578 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010579 it.AdvanceToArgumentsFrame();
10580 frame_inspector.SetArgumentsFrame(it.frame());
10581 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010582
10583 // Find the number of arguments to fill. At least fill the number of
10584 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010585 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010586 if (argument_count < frame_inspector.GetParametersCount()) {
10587 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010588 }
10589
10590 // Calculate the size of the result.
10591 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010592 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010593 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010594 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010595
10596 // Add the frame id.
10597 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10598
10599 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010600 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010601
10602 // Add the arguments count.
10603 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10604
10605 // Add the locals count
10606 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010607 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010608
10609 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010610 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010611 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10612 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010613 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010614 }
10615
10616 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010617 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010618
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010619 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010620 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010621
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010622 // Add flags to indicate information on whether this frame is
10623 // bit 0: invoked in the debugger context.
10624 // bit 1: optimized frame.
10625 // bit 2: inlined in optimized frame
10626 int flags = 0;
10627 if (*save->context() == *isolate->debug()->debug_context()) {
10628 flags |= 1 << 0;
10629 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010630 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010631 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010632 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010633 }
10634 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010635
10636 // Fill the dynamic part.
10637 int details_index = kFrameDetailsFirstDynamicIndex;
10638
10639 // Add arguments name and value.
10640 for (int i = 0; i < argument_count; i++) {
10641 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010642 if (i < scope_info->ParameterCount()) {
10643 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010645 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010646 }
10647
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010648 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010649 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010650 // Get the value from the stack.
10651 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010652 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010653 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010654 }
10655 }
10656
10657 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010658 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010659 details->set(details_index++, locals->get(i));
10660 }
10661
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010662 // Add the value being returned.
10663 if (at_return) {
10664 details->set(details_index++, *return_value);
10665 }
10666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010667 // Add the receiver (same as in function frame).
10668 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10669 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010670 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010671 if (!receiver->IsJSObject() &&
10672 shared->is_classic_mode() &&
10673 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010674 // If the receiver is not a JSObject and the function is not a
10675 // builtin or strict-mode we have hit an optimization where a
10676 // value object is not converted into a wrapped JS objects. To
10677 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010678 // by creating correct wrapper object based on the calling frame's
10679 // global context.
10680 it.Advance();
10681 Handle<Context> calling_frames_global_context(
10682 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010683 receiver =
10684 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010685 }
10686 details->set(kFrameDetailsReceiverIndex, *receiver);
10687
10688 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010689 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690}
10691
10692
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010693// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010694static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010695 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010696 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010697 Handle<Context> context,
10698 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010699 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010700 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10701 VariableMode mode;
10702 InitializationFlag init_flag;
10703 int context_index = scope_info->ContextSlotIndex(
10704 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010705
whesse@chromium.org7b260152011-06-20 15:33:18 +000010706 RETURN_IF_EMPTY_HANDLE_VALUE(
10707 isolate,
10708 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010709 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000010710 Handle<Object>(context->get(context_index), isolate),
10711 NONE,
10712 kNonStrictMode),
10713 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010714 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010715
10716 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010717}
10718
10719
10720// Create a plain JSObject which materializes the local scope for the specified
10721// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010722static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010723 Isolate* isolate,
10724 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010725 FrameInspector* frame_inspector) {
10726 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010727 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010728 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010729
10730 // Allocate and initialize a JSObject with all the arguments, stack locals
10731 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010732 Handle<JSObject> local_scope =
10733 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010734
10735 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010736 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010737 Handle<Object> value(
10738 i < frame_inspector->GetParametersCount() ?
10739 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
10740
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010741 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010742 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010743 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010744 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010745 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010746 NONE,
10747 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010748 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010749 }
10750
10751 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010752 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010753 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010754 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010755 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010756 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010757 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010758 NONE,
10759 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010760 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010761 }
10762
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010763 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010764 // Third fill all context locals.
10765 Handle<Context> frame_context(Context::cast(frame->context()));
10766 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010767 if (!CopyContextLocalsToScopeObject(
10768 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010769 return Handle<JSObject>();
10770 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010771
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010772 // Finally copy any properties from the function context extension.
10773 // These will be variables introduced by eval.
10774 if (function_context->closure() == *function) {
10775 if (function_context->has_extension() &&
10776 !function_context->IsGlobalContext()) {
10777 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010778 bool threw = false;
10779 Handle<FixedArray> keys =
10780 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10781 if (threw) return Handle<JSObject>();
10782
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010783 for (int i = 0; i < keys->length(); i++) {
10784 // Names of variables introduced by eval are strings.
10785 ASSERT(keys->get(i)->IsString());
10786 Handle<String> key(String::cast(keys->get(i)));
10787 RETURN_IF_EMPTY_HANDLE_VALUE(
10788 isolate,
10789 SetProperty(local_scope,
10790 key,
10791 GetProperty(ext, key),
10792 NONE,
10793 kNonStrictMode),
10794 Handle<JSObject>());
10795 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010796 }
10797 }
10798 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010799
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010800 return local_scope;
10801}
10802
10803
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010804static Handle<JSObject> MaterializeLocalScope(
10805 Isolate* isolate,
10806 JavaScriptFrame* frame,
10807 int inlined_jsframe_index) {
10808 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
10809 return MaterializeLocalScopeWithFrameInspector(isolate,
10810 frame,
10811 &frame_inspector);
10812}
10813
10814
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010815// Create a plain JSObject which materializes the closure content for the
10816// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010817static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10818 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010819 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010820
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010821 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010822 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010823
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010824 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010825 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010826 Handle<JSObject> closure_scope =
10827 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010828
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010829 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010830 if (!CopyContextLocalsToScopeObject(
10831 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010832 return Handle<JSObject>();
10833 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010834
10835 // Finally copy any properties from the function context extension. This will
10836 // be variables introduced by eval.
10837 if (context->has_extension()) {
10838 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010839 bool threw = false;
10840 Handle<FixedArray> keys =
10841 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10842 if (threw) return Handle<JSObject>();
10843
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010844 for (int i = 0; i < keys->length(); i++) {
10845 // Names of variables introduced by eval are strings.
10846 ASSERT(keys->get(i)->IsString());
10847 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010848 RETURN_IF_EMPTY_HANDLE_VALUE(
10849 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010850 SetProperty(closure_scope,
10851 key,
10852 GetProperty(ext, key),
10853 NONE,
10854 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010855 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010856 }
10857 }
10858
10859 return closure_scope;
10860}
10861
10862
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010863// Create a plain JSObject which materializes the scope for the specified
10864// catch context.
10865static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10866 Handle<Context> context) {
10867 ASSERT(context->IsCatchContext());
10868 Handle<String> name(String::cast(context->extension()));
10869 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10870 Handle<JSObject> catch_scope =
10871 isolate->factory()->NewJSObject(isolate->object_function());
10872 RETURN_IF_EMPTY_HANDLE_VALUE(
10873 isolate,
10874 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10875 Handle<JSObject>());
10876 return catch_scope;
10877}
10878
10879
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010880// Create a plain JSObject which materializes the block scope for the specified
10881// block context.
10882static Handle<JSObject> MaterializeBlockScope(
10883 Isolate* isolate,
10884 Handle<Context> context) {
10885 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010886 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010887
10888 // Allocate and initialize a JSObject with all the arguments, stack locals
10889 // heap locals and extension properties of the debugged function.
10890 Handle<JSObject> block_scope =
10891 isolate->factory()->NewJSObject(isolate->object_function());
10892
10893 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010894 if (!CopyContextLocalsToScopeObject(
10895 isolate, scope_info, context, block_scope)) {
10896 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010897 }
10898
10899 return block_scope;
10900}
10901
10902
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010903// Create a plain JSObject which materializes the module scope for the specified
10904// module context.
10905static Handle<JSObject> MaterializeModuleScope(
10906 Isolate* isolate,
10907 Handle<Context> context) {
10908 ASSERT(context->IsModuleContext());
10909 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
10910
10911 // Allocate and initialize a JSObject with all the members of the debugged
10912 // module.
10913 Handle<JSObject> module_scope =
10914 isolate->factory()->NewJSObject(isolate->object_function());
10915
10916 // Fill all context locals.
10917 if (!CopyContextLocalsToScopeObject(
10918 isolate, scope_info, context, module_scope)) {
10919 return Handle<JSObject>();
10920 }
10921
10922 return module_scope;
10923}
10924
10925
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010926// Iterate over the actual scopes visible from a stack frame. The iteration
10927// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010928// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010929// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010930class ScopeIterator {
10931 public:
10932 enum ScopeType {
10933 ScopeTypeGlobal = 0,
10934 ScopeTypeLocal,
10935 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010936 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010937 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010938 ScopeTypeBlock,
10939 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010940 };
10941
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010942 ScopeIterator(Isolate* isolate,
10943 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010944 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010945 : isolate_(isolate),
10946 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010947 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010948 function_(JSFunction::cast(frame->function())),
10949 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010950 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010951
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010952 // Catch the case when the debugger stops in an internal function.
10953 Handle<SharedFunctionInfo> shared_info(function_->shared());
10954 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10955 if (shared_info->script() == isolate->heap()->undefined_value()) {
10956 while (context_->closure() == *function_) {
10957 context_ = Handle<Context>(context_->previous(), isolate_);
10958 }
10959 return;
10960 }
10961
10962 // Get the debug info (create it if it does not exist).
10963 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
10964 // Return if ensuring debug info failed.
10965 return;
10966 }
10967 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
10968
10969 // Find the break point where execution has stopped.
10970 BreakLocationIterator break_location_iterator(debug_info,
10971 ALL_BREAK_LOCATIONS);
10972 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
10973 if (break_location_iterator.IsExit()) {
10974 // We are within the return sequence. At the momemt it is not possible to
10975 // get a source position which is consistent with the current scope chain.
10976 // Thus all nested with, catch and block contexts are skipped and we only
10977 // provide the function scope.
10978 if (scope_info->HasContext()) {
10979 context_ = Handle<Context>(context_->declaration_context(), isolate_);
10980 } else {
10981 while (context_->closure() == *function_) {
10982 context_ = Handle<Context>(context_->previous(), isolate_);
10983 }
10984 }
10985 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
10986 } else {
10987 // Reparse the code and analyze the scopes.
10988 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
10989 Handle<Script> script(Script::cast(shared_info->script()));
10990 Scope* scope = NULL;
10991
10992 // Check whether we are in global, eval or function code.
10993 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10994 if (scope_info->Type() != FUNCTION_SCOPE) {
10995 // Global or eval code.
10996 CompilationInfo info(script);
10997 if (scope_info->Type() == GLOBAL_SCOPE) {
10998 info.MarkAsGlobal();
10999 } else {
11000 ASSERT(scope_info->Type() == EVAL_SCOPE);
11001 info.MarkAsEval();
11002 info.SetCallingContext(Handle<Context>(function_->context()));
11003 }
11004 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11005 scope = info.function()->scope();
11006 }
11007 } else {
11008 // Function code
11009 CompilationInfo info(shared_info);
11010 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11011 scope = info.function()->scope();
11012 }
11013 }
11014
11015 // Retrieve the scope chain for the current position.
11016 if (scope != NULL) {
11017 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11018 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11019 } else {
11020 // A failed reparse indicates that the preparser has diverged from the
11021 // parser or that the preparse data given to the initial parse has been
11022 // faulty. We fail in debug mode but in release mode we only provide the
11023 // information we get from the context chain but nothing about
11024 // completely stack allocated scopes or stack allocated locals.
11025 UNREACHABLE();
11026 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011027 }
11028 }
11029
11030 // More scopes?
11031 bool Done() { return context_.is_null(); }
11032
11033 // Move to the next scope.
11034 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011035 ScopeType scope_type = Type();
11036 if (scope_type == ScopeTypeGlobal) {
11037 // The global scope is always the last in the chain.
11038 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011039 context_ = Handle<Context>();
11040 return;
11041 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011042 if (nested_scope_chain_.is_empty()) {
11043 context_ = Handle<Context>(context_->previous(), isolate_);
11044 } else {
11045 if (nested_scope_chain_.last()->HasContext()) {
11046 ASSERT(context_->previous() != NULL);
11047 context_ = Handle<Context>(context_->previous(), isolate_);
11048 }
11049 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011050 }
11051 }
11052
11053 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011054 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011055 if (!nested_scope_chain_.is_empty()) {
11056 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11057 switch (scope_info->Type()) {
11058 case FUNCTION_SCOPE:
11059 ASSERT(context_->IsFunctionContext() ||
11060 !scope_info->HasContext());
11061 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011062 case MODULE_SCOPE:
11063 ASSERT(context_->IsModuleContext());
11064 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011065 case GLOBAL_SCOPE:
11066 ASSERT(context_->IsGlobalContext());
11067 return ScopeTypeGlobal;
11068 case WITH_SCOPE:
11069 ASSERT(context_->IsWithContext());
11070 return ScopeTypeWith;
11071 case CATCH_SCOPE:
11072 ASSERT(context_->IsCatchContext());
11073 return ScopeTypeCatch;
11074 case BLOCK_SCOPE:
11075 ASSERT(!scope_info->HasContext() ||
11076 context_->IsBlockContext());
11077 return ScopeTypeBlock;
11078 case EVAL_SCOPE:
11079 UNREACHABLE();
11080 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011081 }
11082 if (context_->IsGlobalContext()) {
11083 ASSERT(context_->global()->IsGlobalObject());
11084 return ScopeTypeGlobal;
11085 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011086 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011087 return ScopeTypeClosure;
11088 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011089 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011090 return ScopeTypeCatch;
11091 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011092 if (context_->IsBlockContext()) {
11093 return ScopeTypeBlock;
11094 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011095 if (context_->IsModuleContext()) {
11096 return ScopeTypeModule;
11097 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011098 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011099 return ScopeTypeWith;
11100 }
11101
11102 // Return the JavaScript object with the content of the current scope.
11103 Handle<JSObject> ScopeObject() {
11104 switch (Type()) {
11105 case ScopeIterator::ScopeTypeGlobal:
11106 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011107 case ScopeIterator::ScopeTypeLocal:
11108 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011109 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011110 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011111 case ScopeIterator::ScopeTypeWith:
11112 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011113 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11114 case ScopeIterator::ScopeTypeCatch:
11115 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011116 case ScopeIterator::ScopeTypeClosure:
11117 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011118 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011119 case ScopeIterator::ScopeTypeBlock:
11120 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011121 case ScopeIterator::ScopeTypeModule:
11122 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011123 }
11124 UNREACHABLE();
11125 return Handle<JSObject>();
11126 }
11127
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011128 Handle<ScopeInfo> CurrentScopeInfo() {
11129 if (!nested_scope_chain_.is_empty()) {
11130 return nested_scope_chain_.last();
11131 } else if (context_->IsBlockContext()) {
11132 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11133 } else if (context_->IsFunctionContext()) {
11134 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11135 }
11136 return Handle<ScopeInfo>::null();
11137 }
11138
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011139 // Return the context for this scope. For the local context there might not
11140 // be an actual context.
11141 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011142 if (Type() == ScopeTypeGlobal ||
11143 nested_scope_chain_.is_empty()) {
11144 return context_;
11145 } else if (nested_scope_chain_.last()->HasContext()) {
11146 return context_;
11147 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011148 return Handle<Context>();
11149 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011150 }
11151
11152#ifdef DEBUG
11153 // Debug print of the content of the current scope.
11154 void DebugPrint() {
11155 switch (Type()) {
11156 case ScopeIterator::ScopeTypeGlobal:
11157 PrintF("Global:\n");
11158 CurrentContext()->Print();
11159 break;
11160
11161 case ScopeIterator::ScopeTypeLocal: {
11162 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011163 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011164 if (!CurrentContext().is_null()) {
11165 CurrentContext()->Print();
11166 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011167 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011168 if (extension->IsJSContextExtensionObject()) {
11169 extension->Print();
11170 }
11171 }
11172 }
11173 break;
11174 }
11175
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011176 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011177 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011178 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011179 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011180
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011181 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011182 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011183 CurrentContext()->extension()->Print();
11184 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011185 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011186
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011187 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011188 PrintF("Closure:\n");
11189 CurrentContext()->Print();
11190 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011191 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011192 if (extension->IsJSContextExtensionObject()) {
11193 extension->Print();
11194 }
11195 }
11196 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011197
11198 default:
11199 UNREACHABLE();
11200 }
11201 PrintF("\n");
11202 }
11203#endif
11204
11205 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011206 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011207 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011208 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011209 Handle<JSFunction> function_;
11210 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011211 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011212
11213 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11214};
11215
11216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011217RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011218 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011219 ASSERT(args.length() == 2);
11220
11221 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011222 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011223 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11224 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011225 if (!maybe_check->ToObject(&check)) return maybe_check;
11226 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011227 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011228
11229 // Get the frame where the debugging is performed.
11230 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011231 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011232 JavaScriptFrame* frame = it.frame();
11233
11234 // Count the visible scopes.
11235 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011236 for (ScopeIterator it(isolate, frame, 0);
11237 !it.Done();
11238 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011239 n++;
11240 }
11241
11242 return Smi::FromInt(n);
11243}
11244
11245
11246static const int kScopeDetailsTypeIndex = 0;
11247static const int kScopeDetailsObjectIndex = 1;
11248static const int kScopeDetailsSize = 2;
11249
11250// Return an array with scope details
11251// args[0]: number: break id
11252// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011253// args[2]: number: inlined frame index
11254// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011255//
11256// The array returned contains the following information:
11257// 0: Scope type
11258// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011259RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011260 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011261 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011262
11263 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011264 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011265 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11266 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011267 if (!maybe_check->ToObject(&check)) return maybe_check;
11268 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011269 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011270 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011271 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011272
11273 // Get the frame where the debugging is performed.
11274 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011275 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011276 JavaScriptFrame* frame = frame_it.frame();
11277
11278 // Find the requested scope.
11279 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011280 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011281 for (; !it.Done() && n < index; it.Next()) {
11282 n++;
11283 }
11284 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011285 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011286 }
11287
11288 // Calculate the size of the result.
11289 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011290 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011291
11292 // Fill in scope details.
11293 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011294 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011295 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011296 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011297
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011298 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011299}
11300
11301
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011302RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011303 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011304 ASSERT(args.length() == 0);
11305
11306#ifdef DEBUG
11307 // Print the scopes for the top frame.
11308 StackFrameLocator locator;
11309 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011310 for (ScopeIterator it(isolate, frame, 0);
11311 !it.Done();
11312 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011313 it.DebugPrint();
11314 }
11315#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011316 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011317}
11318
11319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011320RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011321 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011322 ASSERT(args.length() == 1);
11323
11324 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011325 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011326 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11327 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011328 if (!maybe_result->ToObject(&result)) return maybe_result;
11329 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011330
11331 // Count all archived V8 threads.
11332 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011333 for (ThreadState* thread =
11334 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011335 thread != NULL;
11336 thread = thread->Next()) {
11337 n++;
11338 }
11339
11340 // Total number of threads is current thread and archived threads.
11341 return Smi::FromInt(n + 1);
11342}
11343
11344
11345static const int kThreadDetailsCurrentThreadIndex = 0;
11346static const int kThreadDetailsThreadIdIndex = 1;
11347static const int kThreadDetailsSize = 2;
11348
11349// Return an array with thread details
11350// args[0]: number: break id
11351// args[1]: number: thread index
11352//
11353// The array returned contains the following information:
11354// 0: Is current thread?
11355// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011356RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011357 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011358 ASSERT(args.length() == 2);
11359
11360 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011361 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011362 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11363 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011364 if (!maybe_check->ToObject(&check)) return maybe_check;
11365 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011366 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11367
11368 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011369 Handle<FixedArray> details =
11370 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011371
11372 // Thread index 0 is current thread.
11373 if (index == 0) {
11374 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011375 details->set(kThreadDetailsCurrentThreadIndex,
11376 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011377 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011378 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011379 } else {
11380 // Find the thread with the requested index.
11381 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011382 ThreadState* thread =
11383 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011384 while (index != n && thread != NULL) {
11385 thread = thread->Next();
11386 n++;
11387 }
11388 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011389 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011390 }
11391
11392 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011393 details->set(kThreadDetailsCurrentThreadIndex,
11394 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011395 details->set(kThreadDetailsThreadIdIndex,
11396 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011397 }
11398
11399 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011400 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011401}
11402
11403
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011404// Sets the disable break state
11405// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011406RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011407 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011408 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011409 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011410 isolate->debug()->set_disable_break(disable_break);
11411 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011412}
11413
11414
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011415RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011416 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011417 ASSERT(args.length() == 1);
11418
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011419 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011420 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011421 // Find the number of break points
11422 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011423 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011424 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011425 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011426 Handle<FixedArray>::cast(break_locations));
11427}
11428
11429
11430// Set a break point in a function
11431// args[0]: function
11432// args[1]: number: break source position (within the function source)
11433// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011434RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011435 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011436 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011437 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011438 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011439 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11440 RUNTIME_ASSERT(source_position >= 0);
11441 Handle<Object> break_point_object_arg = args.at<Object>(2);
11442
11443 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011444 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11445 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011446
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011447 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011448}
11449
11450
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011451Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11452 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011453 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011454 // Iterate the heap looking for SharedFunctionInfo generated from the
11455 // script. The inner most SharedFunctionInfo containing the source position
11456 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011457 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011458 // which is found is not compiled it is compiled and the heap is iterated
11459 // again as the compilation might create inner functions from the newly
11460 // compiled function and the actual requested break point might be in one of
11461 // these functions.
11462 bool done = false;
11463 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011464 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011465 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011466 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011467 { // Extra scope for iterator and no-allocation.
11468 isolate->heap()->EnsureHeapIsIterable();
11469 AssertNoAllocation no_alloc_during_heap_iteration;
11470 HeapIterator iterator;
11471 for (HeapObject* obj = iterator.next();
11472 obj != NULL; obj = iterator.next()) {
11473 if (obj->IsSharedFunctionInfo()) {
11474 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11475 if (shared->script() == *script) {
11476 // If the SharedFunctionInfo found has the requested script data and
11477 // contains the source position it is a candidate.
11478 int start_position = shared->function_token_position();
11479 if (start_position == RelocInfo::kNoPosition) {
11480 start_position = shared->start_position();
11481 }
11482 if (start_position <= position &&
11483 position <= shared->end_position()) {
11484 // If there is no candidate or this function is within the current
11485 // candidate this is the new candidate.
11486 if (target.is_null()) {
11487 target_start_position = start_position;
11488 target = shared;
11489 } else {
11490 if (target_start_position == start_position &&
11491 shared->end_position() == target->end_position()) {
11492 // If a top-level function contain only one function
11493 // declartion the source for the top-level and the
11494 // function is the same. In that case prefer the non
11495 // top-level function.
11496 if (!shared->is_toplevel()) {
11497 target_start_position = start_position;
11498 target = shared;
11499 }
11500 } else if (target_start_position <= start_position &&
11501 shared->end_position() <= target->end_position()) {
11502 // This containment check includes equality as a function
11503 // inside a top-level function can share either start or end
11504 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011505 target_start_position = start_position;
11506 target = shared;
11507 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011508 }
11509 }
11510 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011511 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011512 } // End for loop.
11513 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011514
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011515 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011516 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011517 }
11518
11519 // If the candidate found is compiled we are done. NOTE: when lazy
11520 // compilation of inner functions is introduced some additional checking
11521 // needs to be done here to compile inner functions.
11522 done = target->is_compiled();
11523 if (!done) {
11524 // If the candidate is not compiled compile it to reveal any inner
11525 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011526 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011527 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011528 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011529
11530 return *target;
11531}
11532
11533
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011534// Changes the state of a break point in a script and returns source position
11535// where break point was set. NOTE: Regarding performance see the NOTE for
11536// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011537// args[0]: script to set break point in
11538// args[1]: number: break source position (within the script source)
11539// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011540RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011541 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011542 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011543 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011544 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11545 RUNTIME_ASSERT(source_position >= 0);
11546 Handle<Object> break_point_object_arg = args.at<Object>(2);
11547
11548 // Get the script from the script wrapper.
11549 RUNTIME_ASSERT(wrapper->value()->IsScript());
11550 Handle<Script> script(Script::cast(wrapper->value()));
11551
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011552 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011553 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011554 if (!result->IsUndefined()) {
11555 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11556 // Find position within function. The script position might be before the
11557 // source position of the first function.
11558 int position;
11559 if (shared->start_position() > source_position) {
11560 position = 0;
11561 } else {
11562 position = source_position - shared->start_position();
11563 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011564 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011565 position += shared->start_position();
11566 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011567 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011568 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011569}
11570
11571
11572// Clear a break point
11573// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011574RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011575 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011576 ASSERT(args.length() == 1);
11577 Handle<Object> break_point_object_arg = args.at<Object>(0);
11578
11579 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011580 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011582 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011583}
11584
11585
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011586// Change the state of break on exceptions.
11587// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11588// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011589RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011591 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011592 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011593 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011594
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011595 // If the number doesn't match an enum value, the ChangeBreakOnException
11596 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011597 ExceptionBreakType type =
11598 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011599 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011600 isolate->debug()->ChangeBreakOnException(type, enable);
11601 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011602}
11603
11604
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011605// Returns the state of break on exceptions
11606// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011607RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011608 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011609 ASSERT(args.length() == 1);
11610 RUNTIME_ASSERT(args[0]->IsNumber());
11611
11612 ExceptionBreakType type =
11613 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011615 return Smi::FromInt(result);
11616}
11617
11618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011619// Prepare for stepping
11620// args[0]: break id for checking execution state
11621// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011622// args[2]: number of times to perform the step, for step out it is the number
11623// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011624RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011626 ASSERT(args.length() == 3);
11627 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011628 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011629 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11630 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011631 if (!maybe_check->ToObject(&check)) return maybe_check;
11632 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011633 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011634 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011635 }
11636
11637 // Get the step action and check validity.
11638 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11639 if (step_action != StepIn &&
11640 step_action != StepNext &&
11641 step_action != StepOut &&
11642 step_action != StepInMin &&
11643 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011644 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011645 }
11646
11647 // Get the number of steps.
11648 int step_count = NumberToInt32(args[2]);
11649 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011650 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011651 }
11652
ager@chromium.orga1645e22009-09-09 19:27:10 +000011653 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011654 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011655
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011656 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011657 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11658 step_count);
11659 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011660}
11661
11662
11663// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011664RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011665 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011666 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011667 isolate->debug()->ClearStepping();
11668 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011669}
11670
11671
11672// Creates a copy of the with context chain. The copy of the context chain is
11673// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011674static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11675 Handle<JSFunction> function,
11676 Handle<Context> base,
11677 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011678 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011679 HandleScope scope(isolate);
11680 List<Handle<ScopeInfo> > scope_chain;
11681 List<Handle<Context> > context_chain;
11682
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011683 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011684 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11685 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11686 ASSERT(!it.Done());
11687 scope_chain.Add(it.CurrentScopeInfo());
11688 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011689 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011690
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011691 // At the end of the chain. Return the base context to link to.
11692 Handle<Context> context = base;
11693
11694 // Iteratively copy and or materialize the nested contexts.
11695 while (!scope_chain.is_empty()) {
11696 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11697 Handle<Context> current = context_chain.RemoveLast();
11698 ASSERT(!(scope_info->HasContext() & current.is_null()));
11699
11700 if (scope_info->Type() == CATCH_SCOPE) {
11701 Handle<String> name(String::cast(current->extension()));
11702 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11703 context =
11704 isolate->factory()->NewCatchContext(function,
11705 context,
11706 name,
11707 thrown_object);
11708 } else if (scope_info->Type() == BLOCK_SCOPE) {
11709 // Materialize the contents of the block scope into a JSObject.
11710 Handle<JSObject> block_scope_object =
11711 MaterializeBlockScope(isolate, current);
11712 if (block_scope_object.is_null()) {
11713 return Handle<Context>::null();
11714 }
11715 // Allocate a new function context for the debug evaluation and set the
11716 // extension object.
11717 Handle<Context> new_context =
11718 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11719 function);
11720 new_context->set_extension(*block_scope_object);
11721 new_context->set_previous(*context);
11722 context = new_context;
11723 } else {
11724 ASSERT(scope_info->Type() == WITH_SCOPE);
11725 ASSERT(current->IsWithContext());
11726 Handle<JSObject> extension(JSObject::cast(current->extension()));
11727 context =
11728 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011729 }
erikcorry0ad885c2011-11-21 13:51:57 +000011730 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011731
11732 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011733}
11734
11735
11736// Helper function to find or create the arguments object for
11737// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011738static Handle<Object> GetArgumentsObject(Isolate* isolate,
11739 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011740 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011741 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011742 Handle<Context> function_context) {
11743 // Try to find the value of 'arguments' to pass as parameter. If it is not
11744 // found (that is the debugged function does not reference 'arguments' and
11745 // does not support eval) then create an 'arguments' object.
11746 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011747 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011748 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011749 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011750 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011751 }
11752 }
11753
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011754 if (scope_info->HasHeapAllocatedLocals()) {
11755 VariableMode mode;
11756 InitializationFlag init_flag;
11757 index = scope_info->ContextSlotIndex(
11758 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011759 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011760 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011761 }
11762 }
11763
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011764 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
11765 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011766 Handle<JSObject> arguments =
11767 isolate->factory()->NewArgumentsObject(function, length);
11768 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011769
11770 AssertNoAllocation no_gc;
11771 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011773 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011775 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011776 return arguments;
11777}
11778
11779
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011780static const char kSourceStr[] =
11781 "(function(arguments,__source__){return eval(__source__);})";
11782
11783
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011785// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011786// extension part has all the parameters and locals of the function on the
11787// stack frame. A function which calls eval with the code to evaluate is then
11788// compiled in this context and called in this context. As this context
11789// replaces the context of the function on the stack frame a new (empty)
11790// function is created as well to be used as the closure for the context.
11791// This function and the context acts as replacements for the function on the
11792// stack frame presenting the same view of the values of parameters and
11793// local variables as if the piece of JavaScript was evaluated at the point
11794// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011795RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011796 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797
11798 // Check the execution state and decode arguments frame and source to be
11799 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011800 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011801 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011802 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11803 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011804 if (!maybe_check_result->ToObject(&check_result)) {
11805 return maybe_check_result;
11806 }
11807 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011808 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011809 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011810 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
11811 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011812 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011813
11814 // Handle the processing of break.
11815 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011816
11817 // Get the frame where the debugging is performed.
11818 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011819 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011820 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011821 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11822 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011823 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011824
11825 // Traverse the saved contexts chain to find the active context for the
11826 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011827 SaveContext* save = FindSavedContextForFrame(isolate, frame);
11828
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011829 SaveContext savex(isolate);
11830 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011831
11832 // Create the (empty) function replacing the function on the stack frame for
11833 // the purpose of evaluating in the context created below. It is important
11834 // that this function does not describe any parameters and local variables
11835 // in the context. If it does then this will cause problems with the lookup
11836 // in Context::Lookup, where context slots for parameters and local variables
11837 // are looked at before the extension object.
11838 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011839 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11840 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011841 go_between->set_context(function->context());
11842#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011843 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
11844 ASSERT(go_between_scope_info->ParameterCount() == 0);
11845 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011846#endif
11847
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011848 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011849 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
11850 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011851 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011852
11853 // Allocate a new context for the debug evaluation and set the extension
11854 // object build.
11855 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011856 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11857 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011858 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011859 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011860 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011861 Handle<Context> function_context;
11862 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011863 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011864 function_context = Handle<Context>(frame_context->declaration_context());
11865 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011866 context = CopyNestedScopeContextChain(isolate,
11867 go_between,
11868 context,
11869 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011870 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011871
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011872 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011873 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011874 context =
11875 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011876 }
11877
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011878 // Wrap the evaluation statement in a new function compiled in the newly
11879 // created context. The function has one parameter which has to be called
11880 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011881 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011882 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011883
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011884 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011885 isolate->factory()->NewStringFromAscii(
11886 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011887
11888 // Currently, the eval code will be executed in non-strict mode,
11889 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011890 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011891 Compiler::CompileEval(function_source,
11892 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011893 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011894 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011895 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011896 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011897 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011898 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011899
11900 // Invoke the result of the compilation to get the evaluation function.
11901 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011902 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011903 Handle<Object> evaluation_function =
11904 Execution::Call(compiled_function, receiver, 0, NULL,
11905 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011906 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011907
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011908 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011909 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011910 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011911 scope_info,
11912 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011913
11914 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011915 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011916 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011917 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
11918 receiver,
11919 ARRAY_SIZE(argv),
11920 argv,
11921 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011922 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011923
11924 // Skip the global proxy as it has no properties and always delegates to the
11925 // real global object.
11926 if (result->IsJSGlobalProxy()) {
11927 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11928 }
11929
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011930 return *result;
11931}
11932
11933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011934RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011935 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011936
11937 // Check the execution state and decode arguments frame and source to be
11938 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011939 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011940 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011941 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11942 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011943 if (!maybe_check_result->ToObject(&check_result)) {
11944 return maybe_check_result;
11945 }
11946 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011947 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
11948 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011949 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011950
11951 // Handle the processing of break.
11952 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011953
11954 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011955 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011956 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011957 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011958 top = top->prev();
11959 }
11960 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011961 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011962 }
11963
11964 // Get the global context now set to the top context from before the
11965 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011966 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011967
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011968 bool is_global = true;
11969
11970 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000011971 // Create a new with context with the additional context information between
11972 // the context of the debugged function and the eval code to be executed.
11973 context = isolate->factory()->NewWithContext(
11974 Handle<JSFunction>(context->closure()),
11975 context,
11976 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011977 is_global = false;
11978 }
11979
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011980 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011981 // Currently, the eval code will be executed in non-strict mode,
11982 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011983 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011984 Compiler::CompileEval(source,
11985 context,
11986 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011987 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011988 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011989 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011990 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011991 Handle<JSFunction>(
11992 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11993 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011994
11995 // Invoke the result of the compilation to get the evaluation function.
11996 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011997 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011998 Handle<Object> result =
11999 Execution::Call(compiled_function, receiver, 0, NULL,
12000 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012001 // Clear the oneshot breakpoints so that the debugger does not step further.
12002 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012003 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012004 return *result;
12005}
12006
12007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012008RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012009 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012010 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012011
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012012 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012013 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012014
12015 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012016 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012017 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12018 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12019 // because using
12020 // instances->set(i, *GetScriptWrapper(script))
12021 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012022 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012023 Handle<JSValue> wrapper = GetScriptWrapper(script);
12024 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012025 }
12026
12027 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012028 Handle<JSObject> result =
12029 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012030 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012031 return *result;
12032}
12033
12034
12035// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012036static int DebugReferencedBy(HeapIterator* iterator,
12037 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012038 Object* instance_filter, int max_references,
12039 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012040 JSFunction* arguments_function) {
12041 NoHandleAllocation ha;
12042 AssertNoAllocation no_alloc;
12043
12044 // Iterate the heap.
12045 int count = 0;
12046 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012047 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012048 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012049 (max_references == 0 || count < max_references)) {
12050 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012051 if (heap_obj->IsJSObject()) {
12052 // Skip context extension objects and argument arrays as these are
12053 // checked in the context of functions using them.
12054 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012055 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012056 obj->map()->constructor() == arguments_function) {
12057 continue;
12058 }
12059
12060 // Check if the JS object has a reference to the object looked for.
12061 if (obj->ReferencesObject(target)) {
12062 // Check instance filter if supplied. This is normally used to avoid
12063 // references from mirror objects (see Runtime_IsInPrototypeChain).
12064 if (!instance_filter->IsUndefined()) {
12065 Object* V = obj;
12066 while (true) {
12067 Object* prototype = V->GetPrototype();
12068 if (prototype->IsNull()) {
12069 break;
12070 }
12071 if (instance_filter == prototype) {
12072 obj = NULL; // Don't add this object.
12073 break;
12074 }
12075 V = prototype;
12076 }
12077 }
12078
12079 if (obj != NULL) {
12080 // Valid reference found add to instance array if supplied an update
12081 // count.
12082 if (instances != NULL && count < instances_size) {
12083 instances->set(count, obj);
12084 }
12085 last = obj;
12086 count++;
12087 }
12088 }
12089 }
12090 }
12091
12092 // Check for circular reference only. This can happen when the object is only
12093 // referenced from mirrors and has a circular reference in which case the
12094 // object is not really alive and would have been garbage collected if not
12095 // referenced from the mirror.
12096 if (count == 1 && last == target) {
12097 count = 0;
12098 }
12099
12100 // Return the number of referencing objects found.
12101 return count;
12102}
12103
12104
12105// Scan the heap for objects with direct references to an object
12106// args[0]: the object to find references to
12107// args[1]: constructor function for instances to exclude (Mirror)
12108// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012109RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012110 ASSERT(args.length() == 3);
12111
12112 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012113 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12114 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012115 // The heap iterator reserves the right to do a GC to make the heap iterable.
12116 // Due to the GC above we know it won't need to do that, but it seems cleaner
12117 // to get the heap iterator constructed before we start having unprotected
12118 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012119
12120 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012121 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012122 Object* instance_filter = args[1];
12123 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12124 instance_filter->IsJSObject());
12125 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12126 RUNTIME_ASSERT(max_references >= 0);
12127
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012128
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012129 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012130 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012131 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012132 JSFunction* arguments_function =
12133 JSFunction::cast(arguments_boilerplate->map()->constructor());
12134
12135 // Get the number of referencing objects.
12136 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012137 HeapIterator heap_iterator;
12138 count = DebugReferencedBy(&heap_iterator,
12139 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012140 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012141
12142 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012143 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012144 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012145 if (!maybe_object->ToObject(&object)) return maybe_object;
12146 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012147 FixedArray* instances = FixedArray::cast(object);
12148
12149 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012150 // AllocateFixedArray above does not make the heap non-iterable.
12151 ASSERT(HEAP->IsHeapIterable());
12152 HeapIterator heap_iterator2;
12153 count = DebugReferencedBy(&heap_iterator2,
12154 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012155 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012156
12157 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012158 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012159 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012160 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012161 if (!maybe_result->ToObject(&result)) return maybe_result;
12162 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012163}
12164
12165
12166// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012167static int DebugConstructedBy(HeapIterator* iterator,
12168 JSFunction* constructor,
12169 int max_references,
12170 FixedArray* instances,
12171 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012172 AssertNoAllocation no_alloc;
12173
12174 // Iterate the heap.
12175 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012176 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012177 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012178 (max_references == 0 || count < max_references)) {
12179 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012180 if (heap_obj->IsJSObject()) {
12181 JSObject* obj = JSObject::cast(heap_obj);
12182 if (obj->map()->constructor() == constructor) {
12183 // Valid reference found add to instance array if supplied an update
12184 // count.
12185 if (instances != NULL && count < instances_size) {
12186 instances->set(count, obj);
12187 }
12188 count++;
12189 }
12190 }
12191 }
12192
12193 // Return the number of referencing objects found.
12194 return count;
12195}
12196
12197
12198// Scan the heap for objects constructed by a specific function.
12199// args[0]: the constructor to find instances of
12200// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012201RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012202 ASSERT(args.length() == 2);
12203
12204 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012205 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12206 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012207
12208 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012209 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012210 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12211 RUNTIME_ASSERT(max_references >= 0);
12212
12213 // Get the number of referencing objects.
12214 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012215 HeapIterator heap_iterator;
12216 count = DebugConstructedBy(&heap_iterator,
12217 constructor,
12218 max_references,
12219 NULL,
12220 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012221
12222 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012223 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012224 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012225 if (!maybe_object->ToObject(&object)) return maybe_object;
12226 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012227 FixedArray* instances = FixedArray::cast(object);
12228
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012229 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012230 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012231 HeapIterator heap_iterator2;
12232 count = DebugConstructedBy(&heap_iterator2,
12233 constructor,
12234 max_references,
12235 instances,
12236 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012237
12238 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012239 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012240 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12241 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012242 if (!maybe_result->ToObject(&result)) return maybe_result;
12243 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012244 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012245}
12246
12247
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012248// Find the effective prototype object as returned by __proto__.
12249// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012250RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012251 ASSERT(args.length() == 1);
12252
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012253 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012254
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012255 // Use the __proto__ accessor.
12256 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012257}
12258
12259
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012260RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012261 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012262 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012263 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012264}
12265
12266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012267RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012268#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012269 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012270 ASSERT(args.length() == 1);
12271 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012272 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012273 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012274 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012275 return Failure::Exception();
12276 }
12277 func->code()->PrintLn();
12278#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012279 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012280}
ager@chromium.org9085a012009-05-11 19:22:57 +000012281
12282
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012283RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012284#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012285 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012286 ASSERT(args.length() == 1);
12287 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012288 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012289 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012290 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012291 return Failure::Exception();
12292 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012293 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012294#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012295 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012296}
12297
12298
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012299RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012300 NoHandleAllocation ha;
12301 ASSERT(args.length() == 1);
12302
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012303 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012304 return f->shared()->inferred_name();
12305}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012306
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012307
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012308static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12309 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012310 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012311 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012312 int counter = 0;
12313 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012314 for (HeapObject* obj = iterator->next();
12315 obj != NULL;
12316 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012317 ASSERT(obj != NULL);
12318 if (!obj->IsSharedFunctionInfo()) {
12319 continue;
12320 }
12321 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12322 if (shared->script() != script) {
12323 continue;
12324 }
12325 if (counter < buffer_size) {
12326 buffer->set(counter, shared);
12327 }
12328 counter++;
12329 }
12330 return counter;
12331}
12332
12333// For a script finds all SharedFunctionInfo's in the heap that points
12334// to this script. Returns JSArray of SharedFunctionInfo wrapped
12335// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012336RUNTIME_FUNCTION(MaybeObject*,
12337 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012338 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012339 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012340 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012341
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012342
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012343 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12344
12345 const int kBufferSize = 32;
12346
12347 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012348 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012349 int number;
12350 {
12351 isolate->heap()->EnsureHeapIsIterable();
12352 AssertNoAllocation no_allocations;
12353 HeapIterator heap_iterator;
12354 Script* scr = *script;
12355 FixedArray* arr = *array;
12356 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12357 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012358 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012359 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012360 isolate->heap()->EnsureHeapIsIterable();
12361 AssertNoAllocation no_allocations;
12362 HeapIterator heap_iterator;
12363 Script* scr = *script;
12364 FixedArray* arr = *array;
12365 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012366 }
12367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012368 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012369 result->set_length(Smi::FromInt(number));
12370
12371 LiveEdit::WrapSharedFunctionInfos(result);
12372
12373 return *result;
12374}
12375
12376// For a script calculates compilation information about all its functions.
12377// The script source is explicitly specified by the second argument.
12378// The source of the actual script is not used, however it is important that
12379// all generated code keeps references to this particular instance of script.
12380// Returns a JSArray of compilation infos. The array is ordered so that
12381// each function with all its descendant is always stored in a continues range
12382// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012383RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012384 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012385 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012386 CONVERT_ARG_CHECKED(JSValue, script, 0);
12387 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012388 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12389
12390 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12391
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012392 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012393 return Failure::Exception();
12394 }
12395
12396 return result;
12397}
12398
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012399// Changes the source of the script to a new_source.
12400// If old_script_name is provided (i.e. is a String), also creates a copy of
12401// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012402RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012403 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012404 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012405 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12406 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012407 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012408
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012409 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12410 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012411
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012412 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12413 new_source,
12414 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012415
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012416 if (old_script->IsScript()) {
12417 Handle<Script> script_handle(Script::cast(old_script));
12418 return *(GetScriptWrapper(script_handle));
12419 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012420 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012421 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012422}
12423
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012424
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012425RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012426 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012427 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012428 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012429 return LiveEdit::FunctionSourceUpdated(shared_info);
12430}
12431
12432
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012433// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012434RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012435 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012436 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012437 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12438 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012439
ager@chromium.orgac091b72010-05-05 07:34:42 +000012440 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012441}
12442
12443// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012444RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012445 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012446 HandleScope scope(isolate);
12447 Handle<Object> function_object(args[0], isolate);
12448 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012449
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012450 if (function_object->IsJSValue()) {
12451 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12452 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012453 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12454 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012455 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012456 }
12457
12458 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12459 } else {
12460 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12461 // and we check it in this function.
12462 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012463
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012464 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012465}
12466
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012467
12468// In a code of a parent function replaces original function as embedded object
12469// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012470RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012471 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012472 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012473
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012474 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12475 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12476 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012477
12478 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12479 subst_wrapper);
12480
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012481 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012482}
12483
12484
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012485// Updates positions of a shared function info (first parameter) according
12486// to script source change. Text change is described in second parameter as
12487// array of groups of 3 numbers:
12488// (change_begin, change_end, change_end_new_position).
12489// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012490RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012491 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012492 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012493 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12494 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012495
ager@chromium.orgac091b72010-05-05 07:34:42 +000012496 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012497}
12498
12499
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012500// For array of SharedFunctionInfo's (each wrapped in JSValue)
12501// checks that none of them have activations on stacks (of any thread).
12502// Returns array of the same length with corresponding results of
12503// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012504RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012505 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012506 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012507 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12508 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012509
ager@chromium.org357bf652010-04-12 11:30:10 +000012510 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012511}
12512
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012513// Compares 2 strings line-by-line, then token-wise and returns diff in form
12514// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12515// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012516RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012517 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012518 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012519 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12520 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012521
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012522 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012523}
12524
12525
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012526// A testing entry. Returns statement position which is the closest to
12527// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012528RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012529 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012530 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012531 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012532 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12533
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012534 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012535
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012536 if (code->kind() != Code::FUNCTION &&
12537 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012538 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012539 }
12540
12541 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012542 int closest_pc = 0;
12543 int distance = kMaxInt;
12544 while (!it.done()) {
12545 int statement_position = static_cast<int>(it.rinfo()->data());
12546 // Check if this break point is closer that what was previously found.
12547 if (source_position <= statement_position &&
12548 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012549 closest_pc =
12550 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012551 distance = statement_position - source_position;
12552 // Check whether we can't get any closer.
12553 if (distance == 0) break;
12554 }
12555 it.next();
12556 }
12557
12558 return Smi::FromInt(closest_pc);
12559}
12560
12561
ager@chromium.org357bf652010-04-12 11:30:10 +000012562// Calls specified function with or without entering the debugger.
12563// This is used in unit tests to run code as if debugger is entered or simply
12564// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012565RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012566 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012567 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012568 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12569 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012570
12571 Handle<Object> result;
12572 bool pending_exception;
12573 {
12574 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012575 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012576 &pending_exception);
12577 } else {
12578 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012579 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012580 &pending_exception);
12581 }
12582 }
12583 if (!pending_exception) {
12584 return *result;
12585 } else {
12586 return Failure::Exception();
12587 }
12588}
12589
12590
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012591// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012592RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012593 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012594 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012595 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12596 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012597 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012598}
12599
12600
12601// Performs a GC.
12602// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012603RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012604 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012605 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012606}
12607
12608
12609// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012610RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012611 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012612 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012613 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012614 }
12615 return Smi::FromInt(usage);
12616}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012617
12618
12619// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012620RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012621#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012622 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012623#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012624 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012625#endif
12626}
12627
12628
12629// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012630RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012631#ifdef LIVE_OBJECT_LIST
12632 return LiveObjectList::Capture();
12633#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012634 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012635#endif
12636}
12637
12638
12639// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012640RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012641#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012642 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012643 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012644 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012645#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012646 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012647#endif
12648}
12649
12650
12651// Generates the response to a debugger request for a dump of the objects
12652// contained in the difference between the captured live object lists
12653// specified by id1 and id2.
12654// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12655// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012656RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012657#ifdef LIVE_OBJECT_LIST
12658 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012659 CONVERT_SMI_ARG_CHECKED(id1, 0);
12660 CONVERT_SMI_ARG_CHECKED(id2, 1);
12661 CONVERT_SMI_ARG_CHECKED(start, 2);
12662 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012663 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012664 EnterDebugger enter_debugger;
12665 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12666#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012667 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012668#endif
12669}
12670
12671
12672// Gets the specified object as requested by the debugger.
12673// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012674RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012675#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012676 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012677 Object* result = LiveObjectList::GetObj(obj_id);
12678 return result;
12679#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012680 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012681#endif
12682}
12683
12684
12685// Gets the obj id for the specified address if valid.
12686// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012687RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012688#ifdef LIVE_OBJECT_LIST
12689 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012690 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012691 Object* result = LiveObjectList::GetObjId(address);
12692 return result;
12693#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012694 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012695#endif
12696}
12697
12698
12699// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012700RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012701#ifdef LIVE_OBJECT_LIST
12702 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012703 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012704 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12705 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12706 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12707 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012708 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012709
12710 Handle<JSObject> instance_filter;
12711 if (args[1]->IsJSObject()) {
12712 instance_filter = args.at<JSObject>(1);
12713 }
12714 bool verbose = false;
12715 if (args[2]->IsBoolean()) {
12716 verbose = args[2]->IsTrue();
12717 }
12718 int start = 0;
12719 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012720 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012721 }
12722 int limit = Smi::kMaxValue;
12723 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012724 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012725 }
12726
12727 return LiveObjectList::GetObjRetainers(obj_id,
12728 instance_filter,
12729 verbose,
12730 start,
12731 limit,
12732 filter_obj);
12733#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012734 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012735#endif
12736}
12737
12738
12739// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012740RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012741#ifdef LIVE_OBJECT_LIST
12742 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012743 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12744 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012745 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12746
12747 Handle<JSObject> instance_filter;
12748 if (args[2]->IsJSObject()) {
12749 instance_filter = args.at<JSObject>(2);
12750 }
12751
12752 Object* result =
12753 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12754 return result;
12755#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012756 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012757#endif
12758}
12759
12760
12761// Generates the response to a debugger request for a list of all
12762// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012763RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012764#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012765 CONVERT_SMI_ARG_CHECKED(start, 0);
12766 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012767 return LiveObjectList::Info(start, count);
12768#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012769 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012770#endif
12771}
12772
12773
12774// Gets a dump of the specified object as requested by the debugger.
12775// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012776RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012777#ifdef LIVE_OBJECT_LIST
12778 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012779 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012780 Object* result = LiveObjectList::PrintObj(obj_id);
12781 return result;
12782#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012783 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012784#endif
12785}
12786
12787
12788// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012789RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012790#ifdef LIVE_OBJECT_LIST
12791 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012792 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012793#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012794 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012795#endif
12796}
12797
12798
12799// Generates the response to a debugger request for a summary of the types
12800// of objects in the difference between the captured live object lists
12801// specified by id1 and id2.
12802// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12803// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012804RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012805#ifdef LIVE_OBJECT_LIST
12806 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012807 CONVERT_SMI_ARG_CHECKED(id1, 0);
12808 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012809 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012810
12811 EnterDebugger enter_debugger;
12812 return LiveObjectList::Summarize(id1, id2, filter_obj);
12813#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012814 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012815#endif
12816}
12817
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012818#endif // ENABLE_DEBUGGER_SUPPORT
12819
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012820
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012821RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012822 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012823 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012824 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012825}
12826
12827
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012828RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012829 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012830 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012831 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012832}
12833
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012834
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012835// Finds the script object from the script data. NOTE: This operation uses
12836// heap traversal to find the function generated for the source position
12837// for the requested break point. For lazily compiled functions several heap
12838// traversals might be required rendering this operation as a rather slow
12839// operation. However for setting break points which is normally done through
12840// some kind of user interaction the performance is not crucial.
12841static Handle<Object> Runtime_GetScriptFromScriptName(
12842 Handle<String> script_name) {
12843 // Scan the heap for Script objects to find the script with the requested
12844 // script data.
12845 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012846 script_name->GetHeap()->EnsureHeapIsIterable();
12847 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012848 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012849 HeapObject* obj = NULL;
12850 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012851 // If a script is found check if it has the script data requested.
12852 if (obj->IsScript()) {
12853 if (Script::cast(obj)->name()->IsString()) {
12854 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12855 script = Handle<Script>(Script::cast(obj));
12856 }
12857 }
12858 }
12859 }
12860
12861 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012862 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012863
12864 // Return the script found.
12865 return GetScriptWrapper(script);
12866}
12867
12868
12869// Get the script object from script data. NOTE: Regarding performance
12870// see the NOTE for GetScriptFromScriptData.
12871// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012872RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012873 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012874
12875 ASSERT(args.length() == 1);
12876
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012877 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012878
12879 // Find the requested script.
12880 Handle<Object> result =
12881 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12882 return *result;
12883}
12884
12885
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012886// Determines whether the given stack frame should be displayed in
12887// a stack trace. The caller is the error constructor that asked
12888// for the stack trace to be collected. The first time a construct
12889// call to this function is encountered it is skipped. The seen_caller
12890// in/out parameter is used to remember if the caller has been seen
12891// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012892static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12893 Object* caller,
12894 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012895 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012896 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012897 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012898 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012899 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12900 Object* raw_fun = frame->function();
12901 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012902 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012903 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012904 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012905 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012906 *seen_caller = true;
12907 return false;
12908 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012909 // Skip all frames until we've seen the caller.
12910 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012911 // Also, skip non-visible built-in functions and any call with the builtins
12912 // object as receiver, so as to not reveal either the builtins object or
12913 // an internal function.
12914 // The --builtins-in-stack-traces command line flag allows including
12915 // internal call sites in the stack trace for debugging purposes.
12916 if (!FLAG_builtins_in_stack_traces) {
12917 JSFunction* fun = JSFunction::cast(raw_fun);
12918 if (frame->receiver()->IsJSBuiltinsObject() ||
12919 (fun->IsBuiltin() && !fun->shared()->native())) {
12920 return false;
12921 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012922 }
12923 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012924}
12925
12926
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012927// Collect the raw data for a stack trace. Returns an array of 4
12928// element segments each containing a receiver, function, code and
12929// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012930RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012931 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012932 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012933 Handle<Object> caller = args.at<Object>(1);
12934 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012935
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012936 HandleScope scope(isolate);
12937 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012938
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012939 limit = Max(limit, 0); // Ensure that limit is not negative.
12940 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012941 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012942 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012943
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012944 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012945 // If the caller parameter is a function we skip frames until we're
12946 // under it before starting to collect.
12947 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012948 int cursor = 0;
12949 int frames_seen = 0;
12950 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012951 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012952 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012953 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012954 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012955 // Set initial size to the maximum inlining level + 1 for the outermost
12956 // function.
12957 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012958 frame->Summarize(&frames);
12959 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012960 if (cursor + 4 > elements->length()) {
12961 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12962 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012963 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012964 for (int i = 0; i < cursor; i++) {
12965 new_elements->set(i, elements->get(i));
12966 }
12967 elements = new_elements;
12968 }
12969 ASSERT(cursor + 4 <= elements->length());
12970
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012971 Handle<Object> recv = frames[i].receiver();
12972 Handle<JSFunction> fun = frames[i].function();
12973 Handle<Code> code = frames[i].code();
12974 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012975 elements->set(cursor++, *recv);
12976 elements->set(cursor++, *fun);
12977 elements->set(cursor++, *code);
12978 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012979 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012980 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012981 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012982 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012983 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012984 // Capture and attach a more detailed stack trace if necessary.
12985 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012986 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012987 return *result;
12988}
12989
12990
ager@chromium.org3811b432009-10-28 14:53:37 +000012991// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012992RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012993 ASSERT_EQ(args.length(), 0);
12994
12995 NoHandleAllocation ha;
12996
12997 const char* version_string = v8::V8::GetVersion();
12998
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012999 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13000 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013001}
13002
13003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013004RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013005 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013006 OS::PrintError("abort: %s\n",
13007 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013008 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013009 OS::Abort();
13010 UNREACHABLE();
13011 return NULL;
13012}
13013
13014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013015RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013016 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013017 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013018 Object* key = args[1];
13019
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013020 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013021 Object* o = cache->get(finger_index);
13022 if (o == key) {
13023 // The fastest case: hit the same place again.
13024 return cache->get(finger_index + 1);
13025 }
13026
13027 for (int i = finger_index - 2;
13028 i >= JSFunctionResultCache::kEntriesIndex;
13029 i -= 2) {
13030 o = cache->get(i);
13031 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013032 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013033 return cache->get(i + 1);
13034 }
13035 }
13036
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013037 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013038 ASSERT(size <= cache->length());
13039
13040 for (int i = size - 2; i > finger_index; i -= 2) {
13041 o = cache->get(i);
13042 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013043 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013044 return cache->get(i + 1);
13045 }
13046 }
13047
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013048 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013049 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013050
13051 Handle<JSFunctionResultCache> cache_handle(cache);
13052 Handle<Object> key_handle(key);
13053 Handle<Object> value;
13054 {
13055 Handle<JSFunction> factory(JSFunction::cast(
13056 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13057 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013058 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013059 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013060 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013061 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013062 value = Execution::Call(factory,
13063 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013064 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013065 argv,
13066 &pending_exception);
13067 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013068 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013069
13070#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013071 if (FLAG_verify_heap) {
13072 cache_handle->JSFunctionResultCacheVerify();
13073 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013074#endif
13075
13076 // Function invocation may have cleared the cache. Reread all the data.
13077 finger_index = cache_handle->finger_index();
13078 size = cache_handle->size();
13079
13080 // If we have spare room, put new data into it, otherwise evict post finger
13081 // entry which is likely to be the least recently used.
13082 int index = -1;
13083 if (size < cache_handle->length()) {
13084 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13085 index = size;
13086 } else {
13087 index = finger_index + JSFunctionResultCache::kEntrySize;
13088 if (index == cache_handle->length()) {
13089 index = JSFunctionResultCache::kEntriesIndex;
13090 }
13091 }
13092
13093 ASSERT(index % 2 == 0);
13094 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13095 ASSERT(index < cache_handle->length());
13096
13097 cache_handle->set(index, *key_handle);
13098 cache_handle->set(index + 1, *value);
13099 cache_handle->set_finger_index(index);
13100
13101#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013102 if (FLAG_verify_heap) {
13103 cache_handle->JSFunctionResultCacheVerify();
13104 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013105#endif
13106
13107 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013108}
13109
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013110
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013111RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013112 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013113 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13114 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013115 return *isolate->factory()->NewJSMessageObject(
13116 type,
13117 arguments,
13118 0,
13119 0,
13120 isolate->factory()->undefined_value(),
13121 isolate->factory()->undefined_value(),
13122 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013123}
13124
13125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013126RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013127 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013128 return message->type();
13129}
13130
13131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013132RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013133 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013134 return message->arguments();
13135}
13136
13137
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013138RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013139 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013140 return Smi::FromInt(message->start_position());
13141}
13142
13143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013144RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013145 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013146 return message->script();
13147}
13148
13149
kasper.lund44510672008-07-25 07:37:58 +000013150#ifdef DEBUG
13151// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13152// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013153RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013154 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013155 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013156#define COUNT_ENTRY(Name, argc, ressize) + 1
13157 int entry_count = 0
13158 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13159 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13160 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13161#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013162 Factory* factory = isolate->factory();
13163 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013164 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013165 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013166#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013167 { \
13168 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013169 Handle<String> name; \
13170 /* Inline runtime functions have an underscore in front of the name. */ \
13171 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013172 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013173 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13174 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013175 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013176 Vector<const char>(#Name, StrLength(#Name))); \
13177 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013178 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013179 pair_elements->set(0, *name); \
13180 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013181 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013182 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013183 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013184 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013185 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013186 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013187 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013188 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013189#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013190 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013191 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013192 return *result;
13193}
kasper.lund44510672008-07-25 07:37:58 +000013194#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013195
13196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013197RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013198 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013199 CONVERT_ARG_CHECKED(String, format, 0);
13200 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013201 String::FlatContent format_content = format->GetFlatContent();
13202 RUNTIME_ASSERT(format_content.IsAscii());
13203 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013204 LOGGER->LogRuntime(chars, elms);
13205 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013206}
13207
13208
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013209RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013210 UNREACHABLE(); // implemented as macro in the parser
13211 return NULL;
13212}
13213
13214
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013215#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13216 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013217 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013218 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13219 }
13220
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013221ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013222ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13223ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13224ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13225ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13226ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13227ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13228ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13229ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13230ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13231ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13232ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13233ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13234ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13235
13236#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13237
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013238
13239RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13240 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013241 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13242 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013243 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13244}
13245
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013246// ----------------------------------------------------------------------------
13247// Implementation of Runtime
13248
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013249#define F(name, number_of_args, result_size) \
13250 { Runtime::k##name, Runtime::RUNTIME, #name, \
13251 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013252
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013253
13254#define I(name, number_of_args, result_size) \
13255 { Runtime::kInline##name, Runtime::INLINE, \
13256 "_" #name, NULL, number_of_args, result_size },
13257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013258static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013259 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013260 INLINE_FUNCTION_LIST(I)
13261 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013262};
13263
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013264
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013265MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13266 Object* dictionary) {
13267 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013268 ASSERT(dictionary != NULL);
13269 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13270 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013271 Object* name_symbol;
13272 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013273 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013274 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13275 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013276 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013277 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13278 String::cast(name_symbol),
13279 Smi::FromInt(i),
13280 PropertyDetails(NONE, NORMAL));
13281 if (!maybe_dictionary->ToObject(&dictionary)) {
13282 // Non-recoverable failure. Calling code must restart heap
13283 // initialization.
13284 return maybe_dictionary;
13285 }
13286 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013287 }
13288 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013289}
13290
13291
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013292const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13293 Heap* heap = name->GetHeap();
13294 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013295 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013296 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013297 int function_index = Smi::cast(smi_index)->value();
13298 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013299 }
13300 return NULL;
13301}
13302
13303
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013304const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013305 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13306}
13307
13308
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013309void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013310 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013311 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013312 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013313 if (isolate->heap()->new_space()->AddFreshPage()) {
13314 return;
13315 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013316 // Try to do a garbage collection; ignore it if it fails. The C
13317 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013318 isolate->heap()->CollectGarbage(failure->allocation_space(),
13319 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013320 } else {
13321 // Handle last resort GC and make sure to allow future allocations
13322 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013323 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013324 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13325 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013326 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013327}
13328
13329
13330} } // namespace v8::internal