blob: a2e569b31ece4a2cc41fe69e885154c6ad34bc49 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000109// Assert that the given argument has a valid value for a StrictModeFlag
110// and store it in a StrictModeFlag variable with the given name.
111#define CONVERT_STRICT_MODE_ARG(name, index) \
112 ASSERT(args[index]->IsSmi()); \
113 ASSERT(args.smi_at(index) == kStrictMode || \
114 args.smi_at(index) == kNonStrictMode); \
115 StrictModeFlag name = \
116 static_cast<StrictModeFlag>(args.smi_at(index));
117
118
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000119// Assert that the given argument has a valid value for a LanguageMode
120// and store it in a LanguageMode variable with the given name.
121#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
122 ASSERT(args[index]->IsSmi()); \
123 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
124 args.smi_at(index) == STRICT_MODE || \
125 args.smi_at(index) == EXTENDED_MODE); \
126 LanguageMode name = \
127 static_cast<LanguageMode>(args.smi_at(index));
128
129
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000130MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
131 JSObject* boilerplate) {
132 StackLimitCheck check(isolate);
133 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 JSObject* copy = JSObject::cast(result);
141
142 // Deep copy local properties.
143 if (copy->HasFastProperties()) {
144 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 for (int i = 0; i < properties->length(); i++) {
146 Object* value = properties->get(i);
147 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000149 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000150 if (!maybe_result->ToObject(&result)) return maybe_result;
151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 }
154 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000155 int nof = copy->map()->inobject_properties();
156 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 Object* value = copy->InObjectPropertyAt(i);
158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000164 }
165 }
166 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 FixedArray* names = FixedArray::cast(result);
172 copy->GetLocalPropertyNames(names, 0);
173 for (int i = 0; i < names->length(); i++) {
174 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000175 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000176 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000177 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000178 // Only deep copy fields from the object literal expression.
179 // In particular, don't try to copy the length attribute of
180 // an array.
181 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000182 Object* value =
183 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000184 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000186 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000187 if (!maybe_result->ToObject(&result)) return maybe_result;
188 }
189 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000190 // Creating object copy for literals. No strict mode needed.
191 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000194 }
195 }
196 }
197
198 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000199 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000200 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000202 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000203 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000204 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000205 if (elements->map() == heap->fixed_cow_array_map()) {
206 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000207#ifdef DEBUG
208 for (int i = 0; i < elements->length(); i++) {
209 ASSERT(!elements->get(i)->IsJSObject());
210 }
211#endif
212 } else {
213 for (int i = 0; i < elements->length(); i++) {
214 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000215 ASSERT(value->IsSmi() ||
216 value->IsTheHole() ||
217 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000218 if (value->IsJSObject()) {
219 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000220 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
221 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000222 if (!maybe_result->ToObject(&result)) return maybe_result;
223 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000224 elements->set(i, result);
225 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000226 }
227 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000228 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000229 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000230 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000231 NumberDictionary* element_dictionary = copy->element_dictionary();
232 int capacity = element_dictionary->Capacity();
233 for (int i = 0; i < capacity; i++) {
234 Object* k = element_dictionary->KeyAt(i);
235 if (element_dictionary->IsKey(k)) {
236 Object* value = element_dictionary->ValueAt(i);
237 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000238 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
240 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000241 if (!maybe_result->ToObject(&result)) return maybe_result;
242 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000243 element_dictionary->ValueAtPut(i, result);
244 }
245 }
246 }
247 break;
248 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000249 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000250 UNIMPLEMENTED();
251 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000252 case EXTERNAL_PIXEL_ELEMENTS:
253 case EXTERNAL_BYTE_ELEMENTS:
254 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
255 case EXTERNAL_SHORT_ELEMENTS:
256 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
257 case EXTERNAL_INT_ELEMENTS:
258 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
259 case EXTERNAL_FLOAT_ELEMENTS:
260 case EXTERNAL_DOUBLE_ELEMENTS:
261 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000262 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000263 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000264 }
265 return copy;
266}
267
268
ager@chromium.org236ad962008-09-25 09:45:57 +0000269static Handle<Map> ComputeObjectLiteralMap(
270 Handle<Context> context,
271 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000272 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000273 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 int properties_length = constant_properties->length();
275 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000276 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000277 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000279 for (int p = 0; p != properties_length; p += 2) {
280 Object* key = constant_properties->get(p);
281 uint32_t element_index = 0;
282 if (key->IsSymbol()) {
283 number_of_symbol_keys++;
284 } else if (key->ToArrayIndex(&element_index)) {
285 // An index key does not require space in the property backing store.
286 number_of_properties--;
287 } else {
288 // Bail out as a non-symbol non-index key makes caching impossible.
289 // ASSERT to make sure that the if condition after the loop is false.
290 ASSERT(number_of_symbol_keys != number_of_properties);
291 break;
292 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000293 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000294 // If we only have symbols and array indices among keys then we can
295 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000297 if ((number_of_symbol_keys == number_of_properties) &&
298 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Handle<FixedArray> keys =
301 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000302 if (number_of_symbol_keys > 0) {
303 int index = 0;
304 for (int p = 0; p < properties_length; p += 2) {
305 Object* key = constant_properties->get(p);
306 if (key->IsSymbol()) {
307 keys->set(index++, key);
308 }
309 }
310 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000312 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000313 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000314 }
315 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000316 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000317 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000318 Handle<Map>(context->object_function()->initial_map()),
319 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000320}
321
322
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000325 Handle<FixedArray> literals,
326 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000327
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000328
329static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000331 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000332 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000333 bool should_have_fast_elements,
334 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000335 // Get the global context from the literals array. This is the
336 // context in which the function was created and we use the object
337 // function from this context to create the object literal. We do
338 // not use the object function from the current global context
339 // because this might be the object function from another context
340 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000341 Handle<Context> context =
342 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000344 // In case we have function literals, we want the object to be in
345 // slow properties mode for now. We don't go in the map cache because
346 // maps with constant functions can't be shared if the functions are
347 // not the same (which is the common case).
348 bool is_result_from_cache = false;
349 Handle<Map> map = has_function_literal
350 ? Handle<Map>(context->object_function()->initial_map())
351 : ComputeObjectLiteralMap(context,
352 constant_properties,
353 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000355 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000356
357 // Normalize the elements of the boilerplate to save space if needed.
358 if (!should_have_fast_elements) NormalizeElements(boilerplate);
359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 // Add the constant properties to the boilerplate.
361 int length = constant_properties->length();
362 bool should_transform =
363 !is_result_from_cache && boilerplate->HasFastProperties();
364 if (should_transform || has_function_literal) {
365 // Normalize the properties of object to avoid n^2 behavior
366 // when extending the object multiple properties. Indicate the number of
367 // properties to be added.
368 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
369 }
370
371 for (int index = 0; index < length; index +=2) {
372 Handle<Object> key(constant_properties->get(index+0), isolate);
373 Handle<Object> value(constant_properties->get(index+1), isolate);
374 if (value->IsFixedArray()) {
375 // The value contains the constant_properties of a
376 // simple object or array literal.
377 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
378 value = CreateLiteralBoilerplate(isolate, literals, array);
379 if (value.is_null()) return value;
380 }
381 Handle<Object> result;
382 uint32_t element_index = 0;
383 if (key->IsSymbol()) {
384 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
385 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000386 result = SetOwnElement(boilerplate,
387 element_index,
388 value,
389 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000390 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000391 Handle<String> name(String::cast(*key));
392 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000393 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
394 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 } else if (key->ToArrayIndex(&element_index)) {
397 // Array index (uint32).
398 result = SetOwnElement(boilerplate,
399 element_index,
400 value,
401 kNonStrictMode);
402 } else {
403 // Non-uint32 number.
404 ASSERT(key->IsNumber());
405 double num = key->Number();
406 char arr[100];
407 Vector<char> buffer(arr, ARRAY_SIZE(arr));
408 const char* str = DoubleToCString(num, buffer);
409 Handle<String> name =
410 isolate->factory()->NewStringFromAscii(CStrVector(str));
411 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
412 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 // If setting the property on the boilerplate throws an
415 // exception, the exception is converted to an empty handle in
416 // the handle based operations. In that case, we need to
417 // convert back to an exception.
418 if (result.is_null()) return result;
419 }
420
421 // Transform to fast properties if necessary. For object literals with
422 // containing function literals we defer this operation until after all
423 // computed properties have been assigned so that we can generate
424 // constant function properties.
425 if (should_transform && !has_function_literal) {
426 TransformToFastProperties(boilerplate,
427 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428 }
429
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000430 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000431}
432
433
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000434static const int kSmiOnlyLiteralMinimumLength = 1024;
435
436
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000437static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000438 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000439 Handle<FixedArray> literals,
440 Handle<FixedArray> elements) {
441 // Create the JSArray.
442 Handle<JSFunction> constructor(
443 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000444 Handle<JSArray> object =
445 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000446
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000447 ElementsKind constant_elements_kind =
448 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
449 Handle<FixedArrayBase> constant_elements_values(
450 FixedArrayBase::cast(elements->get(1)));
451
452 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
453 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
454 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
455 constant_elements_kind > object->GetElementsKind();
456
457 if (!FLAG_smi_only_arrays &&
458 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
459 constant_elements_kind != object->GetElementsKind()) {
460 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000461 }
462
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000463 // If the ElementsKind of the constant values of the array literal are less
464 // specific than the ElementsKind of the boilerplate array object, change the
465 // boilerplate array object's map to reflect that kind.
466 if (allow_literal_kind_transition) {
467 Handle<Map> transitioned_array_map =
468 isolate->factory()->GetElementsTransitionMap(object,
469 constant_elements_kind);
470 object->set_map(*transitioned_array_map);
471 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000472
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000473 Handle<FixedArrayBase> copied_elements_values;
474 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
475 ASSERT(FLAG_smi_only_arrays);
476 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
477 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000478 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000479 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
480 constant_elements_kind == FAST_ELEMENTS);
481 const bool is_cow =
482 (constant_elements_values->map() ==
483 isolate->heap()->fixed_cow_array_map());
484 if (is_cow) {
485 copied_elements_values = constant_elements_values;
486#if DEBUG
487 Handle<FixedArray> fixed_array_values =
488 Handle<FixedArray>::cast(copied_elements_values);
489 for (int i = 0; i < fixed_array_values->length(); i++) {
490 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
491 }
492#endif
493 } else {
494 Handle<FixedArray> fixed_array_values =
495 Handle<FixedArray>::cast(constant_elements_values);
496 Handle<FixedArray> fixed_array_values_copy =
497 isolate->factory()->CopyFixedArray(fixed_array_values);
498 copied_elements_values = fixed_array_values_copy;
499 for (int i = 0; i < fixed_array_values->length(); i++) {
500 Object* current = fixed_array_values->get(i);
501 if (current->IsFixedArray()) {
502 // The value contains the constant_properties of a
503 // simple object or array literal.
504 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
505 Handle<Object> result =
506 CreateLiteralBoilerplate(isolate, literals, fa);
507 if (result.is_null()) return result;
508 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000509 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000510 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000511 }
512 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000513 object->set_elements(*copied_elements_values);
514 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000515 return object;
516}
517
518
519static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000521 Handle<FixedArray> literals,
522 Handle<FixedArray> array) {
523 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000525 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000527 return CreateObjectLiteralBoilerplate(isolate,
528 literals,
529 elements,
530 true,
531 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000532 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 return CreateObjectLiteralBoilerplate(isolate,
534 literals,
535 elements,
536 false,
537 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000538 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000540 default:
541 UNREACHABLE();
542 return Handle<Object>::null();
543 }
544}
545
546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000547RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000548 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000549 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000551 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000553 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
555 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000556
557 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 Handle<Object> boilerplate(literals->get(literals_index), isolate);
559 if (*boilerplate == isolate->heap()->undefined_value()) {
560 boilerplate = CreateObjectLiteralBoilerplate(isolate,
561 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000562 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 should_have_fast_elements,
564 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565 if (boilerplate.is_null()) return Failure::Exception();
566 // Update the functions literal and return the boilerplate.
567 literals->set(literals_index, *boilerplate);
568 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000570}
571
572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000573RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000575 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000577 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000579 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000580 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
581 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000582
583 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 Handle<Object> boilerplate(literals->get(literals_index), isolate);
585 if (*boilerplate == isolate->heap()->undefined_value()) {
586 boilerplate = CreateObjectLiteralBoilerplate(isolate,
587 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000588 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 should_have_fast_elements,
590 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000591 if (boilerplate.is_null()) return Failure::Exception();
592 // Update the functions literal and return the boilerplate.
593 literals->set(literals_index, *boilerplate);
594 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000595 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000596}
597
598
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000599RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601 ASSERT(args.length() == 3);
602 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000603 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000604 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
605
606 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000607 Handle<Object> boilerplate(literals->get(literals_index), isolate);
608 if (*boilerplate == isolate->heap()->undefined_value()) {
609 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000610 if (boilerplate.is_null()) return Failure::Exception();
611 // Update the functions literal and return the boilerplate.
612 literals->set(literals_index, *boilerplate);
613 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000615}
616
617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000620 ASSERT(args.length() == 3);
621 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000622 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000623 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
624
625 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 Handle<Object> boilerplate(literals->get(literals_index), isolate);
627 if (*boilerplate == isolate->heap()->undefined_value()) {
628 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000629 if (boilerplate.is_null()) return Failure::Exception();
630 // Update the functions literal and return the boilerplate.
631 literals->set(literals_index, *boilerplate);
632 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000633 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000634 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000635 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000636 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000637 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000638}
639
640
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000641RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
642 ASSERT(args.length() == 2);
643 Object* handler = args[0];
644 Object* prototype = args[1];
645 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000646 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000647 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
648}
649
650
lrn@chromium.org34e60782011-09-15 07:25:40 +0000651RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
652 ASSERT(args.length() == 4);
653 Object* handler = args[0];
654 Object* call_trap = args[1];
655 Object* construct_trap = args[2];
656 Object* prototype = args[3];
657 Object* used_prototype =
658 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
659 return isolate->heap()->AllocateJSFunctionProxy(
660 handler, call_trap, construct_trap, used_prototype);
661}
662
663
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
665 ASSERT(args.length() == 1);
666 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000667 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000668}
669
670
lrn@chromium.org34e60782011-09-15 07:25:40 +0000671RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
672 ASSERT(args.length() == 1);
673 Object* obj = args[0];
674 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
675}
676
677
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000678RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
679 ASSERT(args.length() == 1);
680 CONVERT_CHECKED(JSProxy, proxy, args[0]);
681 return proxy->handler();
682}
683
684
lrn@chromium.org34e60782011-09-15 07:25:40 +0000685RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
686 ASSERT(args.length() == 1);
687 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
688 return proxy->call_trap();
689}
690
691
692RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
693 ASSERT(args.length() == 1);
694 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
695 return proxy->construct_trap();
696}
697
698
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000699RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
700 ASSERT(args.length() == 1);
701 CONVERT_CHECKED(JSProxy, proxy, args[0]);
702 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000703 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000704}
705
706
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000707RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
708 HandleScope scope(isolate);
709 ASSERT(args.length() == 1);
710 CONVERT_ARG_CHECKED(JSSet, holder, 0);
711 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
712 holder->set_table(*table);
713 return *holder;
714}
715
716
717RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
718 HandleScope scope(isolate);
719 ASSERT(args.length() == 2);
720 CONVERT_ARG_CHECKED(JSSet, holder, 0);
721 Handle<Object> key(args[1]);
722 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
723 table = ObjectHashSetAdd(table, key);
724 holder->set_table(*table);
725 return isolate->heap()->undefined_symbol();
726}
727
728
729RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
730 HandleScope scope(isolate);
731 ASSERT(args.length() == 2);
732 CONVERT_ARG_CHECKED(JSSet, holder, 0);
733 Handle<Object> key(args[1]);
734 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
735 return isolate->heap()->ToBoolean(table->Contains(*key));
736}
737
738
739RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
740 HandleScope scope(isolate);
741 ASSERT(args.length() == 2);
742 CONVERT_ARG_CHECKED(JSSet, holder, 0);
743 Handle<Object> key(args[1]);
744 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
745 table = ObjectHashSetRemove(table, key);
746 holder->set_table(*table);
747 return isolate->heap()->undefined_symbol();
748}
749
750
751RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
752 HandleScope scope(isolate);
753 ASSERT(args.length() == 1);
754 CONVERT_ARG_CHECKED(JSMap, holder, 0);
755 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
756 holder->set_table(*table);
757 return *holder;
758}
759
760
761RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
762 HandleScope scope(isolate);
763 ASSERT(args.length() == 2);
764 CONVERT_ARG_CHECKED(JSMap, holder, 0);
765 Handle<Object> key(args[1]);
766 return ObjectHashTable::cast(holder->table())->Lookup(*key);
767}
768
769
770RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
771 HandleScope scope(isolate);
772 ASSERT(args.length() == 3);
773 CONVERT_ARG_CHECKED(JSMap, holder, 0);
774 Handle<Object> key(args[1]);
775 Handle<Object> value(args[2]);
776 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
777 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
778 holder->set_table(*new_table);
779 return *value;
780}
781
782
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000783RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
784 HandleScope scope(isolate);
785 ASSERT(args.length() == 1);
786 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
787 ASSERT(weakmap->map()->inobject_properties() == 0);
788 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
789 weakmap->set_table(*table);
790 weakmap->set_next(Smi::FromInt(0));
791 return *weakmap;
792}
793
794
795RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
796 NoHandleAllocation ha;
797 ASSERT(args.length() == 2);
798 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000799 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
800 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000801}
802
803
804RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
805 HandleScope scope(isolate);
806 ASSERT(args.length() == 3);
807 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000808 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000809 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000810 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000811 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
812 weakmap->set_table(*new_table);
813 return *value;
814}
815
816
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000817RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000818 NoHandleAllocation ha;
819 ASSERT(args.length() == 1);
820 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000821 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000822 return JSObject::cast(obj)->class_name();
823}
824
ager@chromium.org7c537e22008-10-16 08:43:32 +0000825
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000826RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
827 NoHandleAllocation ha;
828 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000829 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
830 Object* obj = input_obj;
831 // We don't expect access checks to be needed on JSProxy objects.
832 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000833 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000834 if (obj->IsAccessCheckNeeded() &&
835 !isolate->MayNamedAccess(JSObject::cast(obj),
836 isolate->heap()->Proto_symbol(),
837 v8::ACCESS_GET)) {
838 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
839 return isolate->heap()->undefined_value();
840 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000841 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000842 } while (obj->IsJSObject() &&
843 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000844 return obj;
845}
846
847
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000848RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000849 NoHandleAllocation ha;
850 ASSERT(args.length() == 2);
851 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
852 Object* O = args[0];
853 Object* V = args[1];
854 while (true) {
855 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000856 if (prototype->IsNull()) return isolate->heap()->false_value();
857 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000858 V = prototype;
859 }
860}
861
862
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000863RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000865 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000866 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000867 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868}
869
870
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000871// Recursively traverses hidden prototypes if property is not found
872static void GetOwnPropertyImplementation(JSObject* obj,
873 String* name,
874 LookupResult* result) {
875 obj->LocalLookupRealNamedProperty(name, result);
876
877 if (!result->IsProperty()) {
878 Object* proto = obj->GetPrototype();
879 if (proto->IsJSObject() &&
880 JSObject::cast(proto)->map()->is_hidden_prototype())
881 GetOwnPropertyImplementation(JSObject::cast(proto),
882 name, result);
883 }
884}
885
886
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000887static bool CheckAccessException(LookupResult* result,
888 v8::AccessType access_type) {
889 if (result->type() == CALLBACKS) {
890 Object* callback = result->GetCallbackObject();
891 if (callback->IsAccessorInfo()) {
892 AccessorInfo* info = AccessorInfo::cast(callback);
893 bool can_access =
894 (access_type == v8::ACCESS_HAS &&
895 (info->all_can_read() || info->all_can_write())) ||
896 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
897 (access_type == v8::ACCESS_SET && info->all_can_write());
898 return can_access;
899 }
900 }
901
902 return false;
903}
904
905
906static bool CheckAccess(JSObject* obj,
907 String* name,
908 LookupResult* result,
909 v8::AccessType access_type) {
910 ASSERT(result->IsProperty());
911
912 JSObject* holder = result->holder();
913 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000914 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000915 while (true) {
916 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000917 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000918 // Access check callback denied the access, but some properties
919 // can have a special permissions which override callbacks descision
920 // (currently see v8::AccessControl).
921 break;
922 }
923
924 if (current == holder) {
925 return true;
926 }
927
928 current = JSObject::cast(current->GetPrototype());
929 }
930
931 // API callbacks can have per callback access exceptions.
932 switch (result->type()) {
933 case CALLBACKS: {
934 if (CheckAccessException(result, access_type)) {
935 return true;
936 }
937 break;
938 }
939 case INTERCEPTOR: {
940 // If the object has an interceptor, try real named properties.
941 // Overwrite the result to fetch the correct property later.
942 holder->LookupRealNamedProperty(name, result);
943 if (result->IsProperty()) {
944 if (CheckAccessException(result, access_type)) {
945 return true;
946 }
947 }
948 break;
949 }
950 default:
951 break;
952 }
953
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000954 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000955 return false;
956}
957
958
959// TODO(1095): we should traverse hidden prototype hierachy as well.
960static bool CheckElementAccess(JSObject* obj,
961 uint32_t index,
962 v8::AccessType access_type) {
963 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000964 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000965 return false;
966 }
967
968 return true;
969}
970
971
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000972// Enumerator used as indices into the array returned from GetOwnProperty
973enum PropertyDescriptorIndices {
974 IS_ACCESSOR_INDEX,
975 VALUE_INDEX,
976 GETTER_INDEX,
977 SETTER_INDEX,
978 WRITABLE_INDEX,
979 ENUMERABLE_INDEX,
980 CONFIGURABLE_INDEX,
981 DESCRIPTOR_SIZE
982};
983
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000984// Returns an array with the property description:
985// if args[1] is not a property on args[0]
986// returns undefined
987// if args[1] is a data property on args[0]
988// [false, value, Writeable, Enumerable, Configurable]
989// if args[1] is an accessor on args[0]
990// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000991RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000992 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000993 Heap* heap = isolate->heap();
994 HandleScope scope(isolate);
995 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
996 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000997 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000998 CONVERT_ARG_CHECKED(JSObject, obj, 0);
999 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001000
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001001 // This could be an element.
1002 uint32_t index;
1003 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001004 switch (obj->HasLocalElement(index)) {
1005 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001006 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001007
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001008 case JSObject::STRING_CHARACTER_ELEMENT: {
1009 // Special handling of string objects according to ECMAScript 5
1010 // 15.5.5.2. Note that this might be a string object with elements
1011 // other than the actual string value. This is covered by the
1012 // subsequent cases.
1013 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1014 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001015 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001017 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001018 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001019 elms->set(WRITABLE_INDEX, heap->false_value());
1020 elms->set(ENUMERABLE_INDEX, heap->false_value());
1021 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001022 return *desc;
1023 }
1024
1025 case JSObject::INTERCEPTED_ELEMENT:
1026 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001027 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001028 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001029 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001030 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001031 elms->set(WRITABLE_INDEX, heap->true_value());
1032 elms->set(ENUMERABLE_INDEX, heap->true_value());
1033 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001034 return *desc;
1035 }
1036
1037 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001038 Handle<JSObject> holder = obj;
1039 if (obj->IsJSGlobalProxy()) {
1040 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001041 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001042 ASSERT(proto->IsJSGlobalObject());
1043 holder = Handle<JSObject>(JSObject::cast(proto));
1044 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001045 FixedArray* elements = FixedArray::cast(holder->elements());
1046 NumberDictionary* dictionary = NULL;
1047 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1048 dictionary = NumberDictionary::cast(elements->get(1));
1049 } else {
1050 dictionary = NumberDictionary::cast(elements);
1051 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001052 int entry = dictionary->FindEntry(index);
1053 ASSERT(entry != NumberDictionary::kNotFound);
1054 PropertyDetails details = dictionary->DetailsAt(entry);
1055 switch (details.type()) {
1056 case CALLBACKS: {
1057 // This is an accessor property with getter and/or setter.
1058 FixedArray* callbacks =
1059 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001061 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1062 elms->set(GETTER_INDEX, callbacks->get(0));
1063 }
1064 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1065 elms->set(SETTER_INDEX, callbacks->get(1));
1066 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001067 break;
1068 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001069 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001070 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001071 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001072 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001073 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001074 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001075 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001076 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001077 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001078 default:
1079 UNREACHABLE();
1080 break;
1081 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001082 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1083 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 return *desc;
1085 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001086 }
1087 }
1088
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001089 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001091
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001092 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001093 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001094 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001095
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001096 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001098 }
1099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001100 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1101 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001102
1103 bool is_js_accessor = (result.type() == CALLBACKS) &&
1104 (result.GetCallbackObject()->IsFixedArray());
1105
1106 if (is_js_accessor) {
1107 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001108 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001109
1110 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1111 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1112 elms->set(GETTER_INDEX, structure->get(0));
1113 }
1114 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1115 elms->set(SETTER_INDEX, structure->get(1));
1116 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001117 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001118 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1119 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001120
1121 PropertyAttributes attrs;
1122 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001123 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001124 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1125 if (!maybe_value->ToObject(&value)) return maybe_value;
1126 }
1127 elms->set(VALUE_INDEX, value);
1128 }
1129
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001130 return *desc;
1131}
1132
1133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001134RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001135 ASSERT(args.length() == 1);
1136 CONVERT_CHECKED(JSObject, obj, args[0]);
1137 return obj->PreventExtensions();
1138}
1139
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001141RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001142 ASSERT(args.length() == 1);
1143 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001144 if (obj->IsJSGlobalProxy()) {
1145 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001146 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001147 ASSERT(proto->IsJSGlobalObject());
1148 obj = JSObject::cast(proto);
1149 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001150 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001151}
1152
1153
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001154RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001155 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001157 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1158 CONVERT_ARG_CHECKED(String, pattern, 1);
1159 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001160 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1161 if (result.is_null()) return Failure::Exception();
1162 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163}
1164
1165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001166RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001167 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001169 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001170 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001171}
1172
1173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001174RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 ASSERT(args.length() == 1);
1176 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001177 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001178 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179}
1180
1181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001182RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001183 ASSERT(args.length() == 2);
1184 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001186 int index = field->value();
1187 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1188 InstanceType type = templ->map()->instance_type();
1189 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1190 type == OBJECT_TEMPLATE_INFO_TYPE);
1191 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001192 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001193 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1194 } else {
1195 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1196 }
1197 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198}
1199
1200
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001201RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001202 ASSERT(args.length() == 1);
1203 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001204 Map* old_map = object->map();
1205 bool needs_access_checks = old_map->is_access_check_needed();
1206 if (needs_access_checks) {
1207 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001208 Object* new_map;
1209 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1210 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1211 }
ager@chromium.org32912102009-01-16 10:38:43 +00001212
1213 Map::cast(new_map)->set_is_access_check_needed(false);
1214 object->set_map(Map::cast(new_map));
1215 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001216 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001217}
1218
1219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001220RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001221 ASSERT(args.length() == 1);
1222 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001223 Map* old_map = object->map();
1224 if (!old_map->is_access_check_needed()) {
1225 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001226 Object* new_map;
1227 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1228 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1229 }
ager@chromium.org32912102009-01-16 10:38:43 +00001230
1231 Map::cast(new_map)->set_is_access_check_needed(true);
1232 object->set_map(Map::cast(new_map));
1233 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001234 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001235}
1236
1237
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001238static Failure* ThrowRedeclarationError(Isolate* isolate,
1239 const char* type,
1240 Handle<String> name) {
1241 HandleScope scope(isolate);
1242 Handle<Object> type_handle =
1243 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 Handle<Object> args[2] = { type_handle, name };
1245 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001246 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1247 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001248}
1249
1250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001251RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001252 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001253 HandleScope scope(isolate);
1254 Handle<GlobalObject> global = Handle<GlobalObject>(
1255 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256
ager@chromium.org3811b432009-10-28 14:53:37 +00001257 Handle<Context> context = args.at<Context>(0);
1258 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001259 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261 // Traverse the name/value pairs and set the properties.
1262 int length = pairs->length();
1263 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001264 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001266 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267
1268 // We have to declare a global const property. To capture we only
1269 // assign to it when evaluating the assignment for "const x =
1270 // <expr>" the initial value is the hole.
1271 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001272 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001273 if (value->IsUndefined() || is_const_property) {
1274 // Lookup the property in the global object, and don't set the
1275 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001276 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 global->Lookup(*name, &lookup);
1278 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001279 // We found an existing property. Unless it was an interceptor
1280 // that claims the property is absent, skip this declaration.
1281 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 continue;
1283 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001284 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1285 if (attributes != ABSENT) {
1286 continue;
1287 }
1288 // Fall-through and introduce the absent property by using
1289 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290 }
1291 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001292 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001294 Handle<SharedFunctionInfo> shared =
1295 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001297 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1298 context,
1299 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 value = function;
1301 }
1302
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001303 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304 global->LocalLookup(*name, &lookup);
1305
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001306 // Compute the property attributes. According to ECMA-262, section
1307 // 13, page 71, the property must be read-only and
1308 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1309 // property as read-only, so we don't either.
1310 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001311 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001312 attr |= DONT_DELETE;
1313 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001314 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001315 if (is_const_property || (is_native && is_function_declaration)) {
1316 attr |= READ_ONLY;
1317 }
1318
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001319 // Safari does not allow the invocation of callback setters for
1320 // function declarations. To mimic this behavior, we do not allow
1321 // the invocation of setters for function values. This makes a
1322 // difference for global functions with the same names as event
1323 // handlers such as "function onload() {}". Firefox does call the
1324 // onload setter in those case and Safari does not. We follow
1325 // Safari for compatibility.
1326 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001327 // Do not change DONT_DELETE to false from true.
1328 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001329 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001330 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001331 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1332
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001333 RETURN_IF_EMPTY_HANDLE(isolate,
1334 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001335 name,
1336 value,
1337 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001339 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1340 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1341 ? kNonStrictMode : kStrictMode;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001342 RETURN_IF_EMPTY_HANDLE(isolate,
1343 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001344 name,
1345 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001346 static_cast<PropertyAttributes>(attr),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001347 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 }
1349 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001351 ASSERT(!isolate->has_pending_exception());
1352 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353}
1354
1355
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001356RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001357 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001358 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001360 // Declarations are always made in a function or global context. In the
1361 // case of eval code, the context passed is the context of the caller,
1362 // which may be some nested context and not the declaration context.
1363 RUNTIME_ASSERT(args[0]->IsContext());
1364 Handle<Context> context(Context::cast(args[0])->declaration_context());
1365
ager@chromium.org7c537e22008-10-16 08:43:32 +00001366 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001367 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001368 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001369 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371 int index;
1372 PropertyAttributes attributes;
1373 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001374 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001375 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001376 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001377
1378 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001379 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001380 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1381 // Functions are not read-only.
1382 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1383 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001384 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385 }
1386
1387 // Initialize it if necessary.
1388 if (*initial_value != NULL) {
1389 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001390 ASSERT(holder.is_identical_to(context));
1391 if (((attributes & READ_ONLY) == 0) ||
1392 context->get(index)->IsTheHole()) {
1393 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001394 }
1395 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001396 // Slow case: The property is in the context extension object of a
1397 // function context or the global object of a global context.
1398 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001399 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001400 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001401 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 }
1403 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001406 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 // "declared" in the function context's extension context or as a
1408 // property of the the global object.
1409 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001410 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001411 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001412 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001413 // Context extension objects are allocated lazily.
1414 ASSERT(context->IsFunctionContext());
1415 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001416 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001417 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001418 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001419 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420
ager@chromium.org7c537e22008-10-16 08:43:32 +00001421 // Declare the property by setting it to the initial value if provided,
1422 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1423 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001426 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001427 // Declaring a const context slot is a conflicting declaration if
1428 // there is a callback with that name in a prototype. It is
1429 // allowed to introduce const variables in
1430 // JSContextExtensionObjects. They are treated specially in
1431 // SetProperty and no setters are invoked for those since they are
1432 // not real JSObjects.
1433 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001434 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001435 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001437 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001438 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001439 }
1440 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001441 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001442 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001443 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001444 }
1445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447}
1448
1449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001450RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001451 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001452 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001453 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001454 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001455
1456 // Determine if we need to assign to the variable if it already
1457 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001458 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1459 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001462 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001464 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1465 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1466 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467
1468 // According to ECMA-262, section 12.2, page 62, the property must
1469 // not be deletable.
1470 PropertyAttributes attributes = DONT_DELETE;
1471
1472 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001473 // there, there is a property with this name in the prototype chain.
1474 // We follow Safari and Firefox behavior and only set the property
1475 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001476 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001477 // Note that objects can have hidden prototypes, so we need to traverse
1478 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001479 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001480 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001481 while (object->IsJSObject() &&
1482 JSObject::cast(object)->map()->is_hidden_prototype()) {
1483 JSObject* raw_holder = JSObject::cast(object);
1484 raw_holder->LocalLookup(*name, &lookup);
1485 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1486 HandleScope handle_scope(isolate);
1487 Handle<JSObject> holder(raw_holder);
1488 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1489 // Update the raw pointer in case it's changed due to GC.
1490 raw_holder = *holder;
1491 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1492 // Found an interceptor that's not read only.
1493 if (assign) {
1494 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001495 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001496 } else {
1497 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001498 }
1499 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001500 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 }
1503
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001504 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001505 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001506 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001507 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001508 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001509 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510}
1511
1512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001513RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 // All constants are declared with an initial value. The name
1515 // of the constant is the first argument and the initial value
1516 // is the second.
1517 RUNTIME_ASSERT(args.length() == 2);
1518 CONVERT_ARG_CHECKED(String, name, 0);
1519 Handle<Object> value = args.at<Object>(1);
1520
1521 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001522 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001523
1524 // According to ECMA-262, section 12.2, page 62, the property must
1525 // not be deletable. Since it's a const, it must be READ_ONLY too.
1526 PropertyAttributes attributes =
1527 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1528
1529 // Lookup the property locally in the global object. If it isn't
1530 // there, we add the property and take special precautions to always
1531 // add it as a local property even in case of callbacks in the
1532 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001533 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001534 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 global->LocalLookup(*name, &lookup);
1536 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001537 return global->SetLocalPropertyIgnoreAttributes(*name,
1538 *value,
1539 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 }
1541
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001544 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001545 HandleScope handle_scope(isolate);
1546 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001548 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549 // property through an interceptor and only do it if it's
1550 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001551 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001552 RETURN_IF_EMPTY_HANDLE(isolate,
1553 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001554 name,
1555 value,
1556 attributes,
1557 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001558 return *value;
1559 }
1560
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001561 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 // constant. For now, we determine this by checking if the
1563 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001564 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565 PropertyType type = lookup.type();
1566 if (type == FIELD) {
1567 FixedArray* properties = global->properties();
1568 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001569 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 properties->set(index, *value);
1571 }
1572 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001573 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1574 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001575 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 }
1577 } else {
1578 // Ignore re-initialization of constants that have already been
1579 // assigned a function value.
1580 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1581 }
1582
1583 // Use the set value as the result of the operation.
1584 return *value;
1585}
1586
1587
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001588RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001589 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590 ASSERT(args.length() == 3);
1591
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001592 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001593 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001595 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001596 RUNTIME_ASSERT(args[1]->IsContext());
1597 Handle<Context> context(Context::cast(args[1])->declaration_context());
1598
1599 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600
1601 int index;
1602 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001603 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001604 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001605 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001606 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001609 ASSERT(holder->IsContext());
1610 // Property was found in a context. Perform the assignment if we
1611 // found some non-constant or an uninitialized constant.
1612 Handle<Context> context = Handle<Context>::cast(holder);
1613 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1614 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001615 }
1616 return *value;
1617 }
1618
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001619 // The property could not be found, we introduce it as a property of the
1620 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001621 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001622 Handle<JSObject> global = Handle<JSObject>(
1623 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001624 // Strict mode not needed (const disallowed in strict mode).
1625 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001626 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001627 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001628 return *value;
1629 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001630
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001631 // The property was present in some function's context extension object,
1632 // as a property on the subject of a with, or as a property of the global
1633 // object.
1634 //
1635 // In most situations, eval-introduced consts should still be present in
1636 // the context extension object. However, because declaration and
1637 // initialization are separate, the property might have been deleted
1638 // before we reach the initialization point.
1639 //
1640 // Example:
1641 //
1642 // function f() { eval("delete x; const x;"); }
1643 //
1644 // In that case, the initialization behaves like a normal assignment.
1645 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001646
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001647 if (*object == context->extension()) {
1648 // This is the property that was introduced by the const declaration.
1649 // Set it if it hasn't been set before. NOTE: We cannot use
1650 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001651 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001652 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001653 ASSERT(lookup.IsProperty()); // the property was declared
1654 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1655
1656 PropertyType type = lookup.type();
1657 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001658 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001659 int index = lookup.GetFieldIndex();
1660 if (properties->get(index)->IsTheHole()) {
1661 properties->set(index, *value);
1662 }
1663 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001664 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1665 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001666 }
1667 } else {
1668 // We should not reach here. Any real, named property should be
1669 // either a field or a dictionary slot.
1670 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001671 }
1672 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001673 // The property was found on some other object. Set it if it is not a
1674 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001675 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001676 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001677 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001678 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001679 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001680 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001681 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001683 return *value;
1684}
1685
1686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001687RUNTIME_FUNCTION(MaybeObject*,
1688 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001689 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001690 ASSERT(args.length() == 2);
1691 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001692 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001693 if (object->HasFastProperties()) {
1694 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1695 }
1696 return *object;
1697}
1698
1699
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001700RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001701 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001702 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001703 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1704 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001705 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001706 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001707 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001708 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001709 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001710 RUNTIME_ASSERT(index >= 0);
1711 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001712 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001713 Handle<Object> result = RegExpImpl::Exec(regexp,
1714 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001715 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001716 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001717 if (result.is_null()) return Failure::Exception();
1718 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719}
1720
1721
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001722RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001723 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001724 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001725 if (elements_count < 0 ||
1726 elements_count > FixedArray::kMaxLength ||
1727 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001728 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001729 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730 Object* new_object;
1731 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001732 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001733 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1734 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001735 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001736 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1737 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001738 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1739 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001740 {
1741 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001742 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001743 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001744 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001745 }
1746 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001748 array->set_elements(elements);
1749 array->set_length(Smi::FromInt(elements_count));
1750 // Write in-object properties after the length of the array.
1751 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1752 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1753 return array;
1754}
1755
1756
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001757RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001758 AssertNoAllocation no_alloc;
1759 ASSERT(args.length() == 5);
1760 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1761 CONVERT_CHECKED(String, source, args[1]);
1762
1763 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001764 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001765
1766 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001767 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001768
1769 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001771
1772 Map* map = regexp->map();
1773 Object* constructor = map->constructor();
1774 if (constructor->IsJSFunction() &&
1775 JSFunction::cast(constructor)->initial_map() == map) {
1776 // If we still have the original map, set in-object properties directly.
1777 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001778 // Both true and false are immovable immortal objects so no need for write
1779 // barrier.
1780 regexp->InObjectPropertyAtPut(
1781 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1782 regexp->InObjectPropertyAtPut(
1783 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1784 regexp->InObjectPropertyAtPut(
1785 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001786 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1787 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001788 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001789 return regexp;
1790 }
1791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001792 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001793 PropertyAttributes final =
1794 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1795 PropertyAttributes writable =
1796 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001797 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001798 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001799 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001800 source,
1801 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001802 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001803 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001804 global,
1805 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001806 ASSERT(!result->IsFailure());
1807 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001809 ignoreCase,
1810 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001811 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001812 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001813 multiline,
1814 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001815 ASSERT(!result->IsFailure());
1816 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001818 Smi::FromInt(0),
1819 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001820 ASSERT(!result->IsFailure());
1821 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001822 return regexp;
1823}
1824
1825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001826RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001828 ASSERT(args.length() == 1);
1829 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1830 // This is necessary to enable fast checks for absence of elements
1831 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001833 return Smi::FromInt(0);
1834}
1835
1836
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001837static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1838 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001839 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001840 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001841 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1842 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1843 Handle<JSFunction> optimized =
1844 isolate->factory()->NewFunction(key,
1845 JS_OBJECT_TYPE,
1846 JSObject::kHeaderSize,
1847 code,
1848 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001849 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001850 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001851 return optimized;
1852}
1853
1854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001855RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001857 ASSERT(args.length() == 1);
1858 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1859
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001860 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1861 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1862 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1863 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1864 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1865 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1866 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001867
1868 return *holder;
1869}
1870
1871
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001872RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1873 NoHandleAllocation handle_free;
1874 ASSERT(args.length() == 1);
1875 CONVERT_CHECKED(JSFunction, function, args[0]);
1876 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001877 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001878 return isolate->heap()->undefined_value();
1879 }
1880 // Returns undefined for strict or native functions, or
1881 // the associated global receiver for "normal" functions.
1882
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001883 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001884 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001885 return global_context->global()->global_receiver();
1886}
1887
1888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001889RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001890 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001891 ASSERT(args.length() == 4);
1892 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001893 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001894 Handle<String> pattern = args.at<String>(2);
1895 Handle<String> flags = args.at<String>(3);
1896
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001897 // Get the RegExp function from the context in the literals array.
1898 // This is the RegExp function from the context in which the
1899 // function was created. We do not use the RegExp function from the
1900 // current global context because this might be the RegExp function
1901 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001902 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001903 Handle<JSFunction>(
1904 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001905 // Compute the regular expression literal.
1906 bool has_pending_exception;
1907 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001908 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1909 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001910 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001911 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 return Failure::Exception();
1913 }
1914 literals->set(index, *regexp);
1915 return *regexp;
1916}
1917
1918
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001919RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001920 NoHandleAllocation ha;
1921 ASSERT(args.length() == 1);
1922
1923 CONVERT_CHECKED(JSFunction, f, args[0]);
1924 return f->shared()->name();
1925}
1926
1927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001928RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001929 NoHandleAllocation ha;
1930 ASSERT(args.length() == 2);
1931
1932 CONVERT_CHECKED(JSFunction, f, args[0]);
1933 CONVERT_CHECKED(String, name, args[1]);
1934 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001935 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001936}
1937
1938
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001939RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1940 NoHandleAllocation ha;
1941 ASSERT(args.length() == 1);
1942 CONVERT_CHECKED(JSFunction, f, args[0]);
1943 return isolate->heap()->ToBoolean(
1944 f->shared()->name_should_print_as_anonymous());
1945}
1946
1947
1948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951 CONVERT_CHECKED(JSFunction, f, args[0]);
1952 f->shared()->set_name_should_print_as_anonymous(true);
1953 return isolate->heap()->undefined_value();
1954}
1955
1956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 1);
1960
1961 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001962 Object* obj = f->RemovePrototype();
1963 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001964
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001965 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001966}
1967
1968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001969RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001970 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001971 ASSERT(args.length() == 1);
1972
1973 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001974 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1975 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976
1977 return *GetScriptWrapper(Handle<Script>::cast(script));
1978}
1979
1980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001981RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001982 NoHandleAllocation ha;
1983 ASSERT(args.length() == 1);
1984
1985 CONVERT_CHECKED(JSFunction, f, args[0]);
1986 return f->shared()->GetSourceCode();
1987}
1988
1989
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001990RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991 NoHandleAllocation ha;
1992 ASSERT(args.length() == 1);
1993
1994 CONVERT_CHECKED(JSFunction, fun, args[0]);
1995 int pos = fun->shared()->start_position();
1996 return Smi::FromInt(pos);
1997}
1998
1999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002000RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002001 ASSERT(args.length() == 2);
2002
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002003 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002004 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2005
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002006 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2007
2008 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002009 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002010}
2011
2012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002013RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014 NoHandleAllocation ha;
2015 ASSERT(args.length() == 2);
2016
2017 CONVERT_CHECKED(JSFunction, fun, args[0]);
2018 CONVERT_CHECKED(String, name, args[1]);
2019 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002020 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021}
2022
2023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002024RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002025 NoHandleAllocation ha;
2026 ASSERT(args.length() == 2);
2027
2028 CONVERT_CHECKED(JSFunction, fun, args[0]);
2029 CONVERT_CHECKED(Smi, length, args[1]);
2030 fun->shared()->set_length(length->value());
2031 return length;
2032}
2033
2034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002035RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002036 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002037 ASSERT(args.length() == 2);
2038
2039 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002040 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002041 Object* obj;
2042 { MaybeObject* maybe_obj =
2043 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2044 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2045 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002046 return args[0]; // return TOS
2047}
2048
2049
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002050RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2051 NoHandleAllocation ha;
2052 RUNTIME_ASSERT(args.length() == 1);
2053 CONVERT_CHECKED(JSFunction, function, args[0]);
2054
2055 MaybeObject* maybe_name =
2056 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2057 String* name;
2058 if (!maybe_name->To(&name)) return maybe_name;
2059
2060 if (function->HasFastProperties()) {
2061 // Construct a new field descriptor with updated attributes.
2062 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2063 int index = instance_desc->Search(name);
2064 ASSERT(index != DescriptorArray::kNotFound);
2065 PropertyDetails details(instance_desc->GetDetails(index));
2066 CallbacksDescriptor new_desc(name,
2067 instance_desc->GetValue(index),
2068 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2069 details.index());
2070 // Construct a new field descriptors array containing the new descriptor.
2071 Object* descriptors_unchecked;
2072 { MaybeObject* maybe_descriptors_unchecked =
2073 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2074 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2075 return maybe_descriptors_unchecked;
2076 }
2077 }
2078 DescriptorArray* new_descriptors =
2079 DescriptorArray::cast(descriptors_unchecked);
2080 // Create a new map featuring the new field descriptors array.
2081 Object* map_unchecked;
2082 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2083 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2084 return maybe_map_unchecked;
2085 }
2086 }
2087 Map* new_map = Map::cast(map_unchecked);
2088 new_map->set_instance_descriptors(new_descriptors);
2089 function->set_map(new_map);
2090 } else { // Dictionary properties.
2091 // Directly manipulate the property details.
2092 int entry = function->property_dictionary()->FindEntry(name);
2093 ASSERT(entry != StringDictionary::kNotFound);
2094 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2095 PropertyDetails new_details(
2096 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2097 details.type(),
2098 details.index());
2099 function->property_dictionary()->DetailsAtPut(entry, new_details);
2100 }
2101 return function;
2102}
2103
2104
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002105RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002106 NoHandleAllocation ha;
2107 ASSERT(args.length() == 1);
2108
2109 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002110 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002111}
2112
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002114RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002115 NoHandleAllocation ha;
2116 ASSERT(args.length() == 1);
2117
2118 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002119 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002120}
2121
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002123RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002124 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002125 ASSERT(args.length() == 2);
2126
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002127 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002128 Handle<Object> code = args.at<Object>(1);
2129
2130 Handle<Context> context(target->context());
2131
2132 if (!code->IsNull()) {
2133 RUNTIME_ASSERT(code->IsJSFunction());
2134 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002135 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002136
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002137 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002138 return Failure::Exception();
2139 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002140 // Since we don't store the source for this we should never
2141 // optimize this.
2142 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002143 // Set the code, scope info, formal parameter count,
2144 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002145 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002146 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002147 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002148 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002149 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002150 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002151 // Set the source code of the target function to undefined.
2152 // SetCode is only used for built-in constructors like String,
2153 // Array, and Object, and some web code
2154 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002155 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002156 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002157 // Clear the optimization hints related to the compiled code as these are no
2158 // longer valid when the code is overwritten.
2159 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002160 context = Handle<Context>(fun->context());
2161
2162 // Make sure we get a fresh copy of the literal vector to avoid
2163 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002164 int number_of_literals = fun->NumberOfLiterals();
2165 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002166 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002167 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002168 // Insert the object, regexp and array functions in the literals
2169 // array prefix. These are the functions that will be used when
2170 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002171 literals->set(JSFunction::kLiteralGlobalContextIndex,
2172 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002174 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002175 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002176
2177 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2178 isolate->logger()->LogExistingFunction(
2179 shared, Handle<Code>(shared->code()));
2180 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002181 }
2182
2183 target->set_context(*context);
2184 return *target;
2185}
2186
2187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002188RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002189 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002190 ASSERT(args.length() == 2);
2191 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002192 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002193 RUNTIME_ASSERT(num >= 0);
2194 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002195 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002196}
2197
2198
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002199MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2200 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002201 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002202 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002203 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002204 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002205 }
2206 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002207 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002208}
2209
2210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002211RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002212 NoHandleAllocation ha;
2213 ASSERT(args.length() == 2);
2214
2215 CONVERT_CHECKED(String, subject, args[0]);
2216 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002217 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002218
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002219 uint32_t i = 0;
2220 if (index->IsSmi()) {
2221 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002222 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002223 i = value;
2224 } else {
2225 ASSERT(index->IsHeapNumber());
2226 double value = HeapNumber::cast(index)->value();
2227 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002228 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002229
2230 // Flatten the string. If someone wants to get a char at an index
2231 // in a cons string, it is likely that more indices will be
2232 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002233 Object* flat;
2234 { MaybeObject* maybe_flat = subject->TryFlatten();
2235 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2236 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002237 subject = String::cast(flat);
2238
2239 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002240 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002241 }
2242
2243 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002244}
2245
2246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002247RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002248 NoHandleAllocation ha;
2249 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002250 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251}
2252
lrn@chromium.org25156de2010-04-06 13:10:27 +00002253
2254class FixedArrayBuilder {
2255 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002256 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2257 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002258 length_(0),
2259 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002260 // Require a non-zero initial size. Ensures that doubling the size to
2261 // extend the array will work.
2262 ASSERT(initial_capacity > 0);
2263 }
2264
2265 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2266 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002267 length_(0),
2268 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002269 // Require a non-zero initial size. Ensures that doubling the size to
2270 // extend the array will work.
2271 ASSERT(backing_store->length() > 0);
2272 }
2273
2274 bool HasCapacity(int elements) {
2275 int length = array_->length();
2276 int required_length = length_ + elements;
2277 return (length >= required_length);
2278 }
2279
2280 void EnsureCapacity(int elements) {
2281 int length = array_->length();
2282 int required_length = length_ + elements;
2283 if (length < required_length) {
2284 int new_length = length;
2285 do {
2286 new_length *= 2;
2287 } while (new_length < required_length);
2288 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002289 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 array_->CopyTo(0, *extended_array, 0, length_);
2291 array_ = extended_array;
2292 }
2293 }
2294
2295 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002296 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002297 ASSERT(length_ < capacity());
2298 array_->set(length_, value);
2299 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002300 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002301 }
2302
2303 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002304 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002305 ASSERT(length_ < capacity());
2306 array_->set(length_, value);
2307 length_++;
2308 }
2309
2310 Handle<FixedArray> array() {
2311 return array_;
2312 }
2313
2314 int length() {
2315 return length_;
2316 }
2317
2318 int capacity() {
2319 return array_->length();
2320 }
2321
2322 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002323 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002324 result_array->set_length(Smi::FromInt(length_));
2325 return result_array;
2326 }
2327
2328 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002329 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002330 target_array->set_length(Smi::FromInt(length_));
2331 return target_array;
2332 }
2333
2334 private:
2335 Handle<FixedArray> array_;
2336 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002337 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002338};
2339
2340
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002341// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002342const int kStringBuilderConcatHelperLengthBits = 11;
2343const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002344
2345template <typename schar>
2346static inline void StringBuilderConcatHelper(String*,
2347 schar*,
2348 FixedArray*,
2349 int);
2350
lrn@chromium.org25156de2010-04-06 13:10:27 +00002351typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2352 StringBuilderSubstringLength;
2353typedef BitField<int,
2354 kStringBuilderConcatHelperLengthBits,
2355 kStringBuilderConcatHelperPositionBits>
2356 StringBuilderSubstringPosition;
2357
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002358
2359class ReplacementStringBuilder {
2360 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002361 ReplacementStringBuilder(Heap* heap,
2362 Handle<String> subject,
2363 int estimated_part_count)
2364 : heap_(heap),
2365 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002366 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002367 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002368 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002369 // Require a non-zero initial size. Ensures that doubling the size to
2370 // extend the array will work.
2371 ASSERT(estimated_part_count > 0);
2372 }
2373
lrn@chromium.org25156de2010-04-06 13:10:27 +00002374 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2375 int from,
2376 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002377 ASSERT(from >= 0);
2378 int length = to - from;
2379 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002380 if (StringBuilderSubstringLength::is_valid(length) &&
2381 StringBuilderSubstringPosition::is_valid(from)) {
2382 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2383 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002384 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002385 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002386 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002387 builder->Add(Smi::FromInt(-length));
2388 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002389 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002390 }
2391
2392
2393 void EnsureCapacity(int elements) {
2394 array_builder_.EnsureCapacity(elements);
2395 }
2396
2397
2398 void AddSubjectSlice(int from, int to) {
2399 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002400 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002401 }
2402
2403
2404 void AddString(Handle<String> string) {
2405 int length = string->length();
2406 ASSERT(length > 0);
2407 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002408 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002409 is_ascii_ = false;
2410 }
2411 IncrementCharacterCount(length);
2412 }
2413
2414
2415 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002416 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002417 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002418 }
2419
2420 Handle<String> joined_string;
2421 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002422 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002423 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002424 char* char_buffer = seq->GetChars();
2425 StringBuilderConcatHelper(*subject_,
2426 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002427 *array_builder_.array(),
2428 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002429 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002430 } else {
2431 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002432 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002433 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002434 uc16* char_buffer = seq->GetChars();
2435 StringBuilderConcatHelper(*subject_,
2436 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002437 *array_builder_.array(),
2438 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002439 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002440 }
2441 return joined_string;
2442 }
2443
2444
2445 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002446 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002447 V8::FatalProcessOutOfMemory("String.replace result too large.");
2448 }
2449 character_count_ += by;
2450 }
2451
lrn@chromium.org25156de2010-04-06 13:10:27 +00002452 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002453 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002454 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002455
lrn@chromium.org25156de2010-04-06 13:10:27 +00002456 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002457 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2458 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002459 }
2460
2461
ager@chromium.org04921a82011-06-27 13:21:41 +00002462 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2463 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002464 }
2465
2466
2467 void AddElement(Object* element) {
2468 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002469 ASSERT(array_builder_.capacity() > array_builder_.length());
2470 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002471 }
2472
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002473 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002474 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002475 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002476 int character_count_;
2477 bool is_ascii_;
2478};
2479
2480
2481class CompiledReplacement {
2482 public:
2483 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002484 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002485
2486 void Compile(Handle<String> replacement,
2487 int capture_count,
2488 int subject_length);
2489
2490 void Apply(ReplacementStringBuilder* builder,
2491 int match_from,
2492 int match_to,
2493 Handle<JSArray> last_match_info);
2494
2495 // Number of distinct parts of the replacement pattern.
2496 int parts() {
2497 return parts_.length();
2498 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002499
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002500 bool simple_hint() {
2501 return simple_hint_;
2502 }
2503
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002504 private:
2505 enum PartType {
2506 SUBJECT_PREFIX = 1,
2507 SUBJECT_SUFFIX,
2508 SUBJECT_CAPTURE,
2509 REPLACEMENT_SUBSTRING,
2510 REPLACEMENT_STRING,
2511
2512 NUMBER_OF_PART_TYPES
2513 };
2514
2515 struct ReplacementPart {
2516 static inline ReplacementPart SubjectMatch() {
2517 return ReplacementPart(SUBJECT_CAPTURE, 0);
2518 }
2519 static inline ReplacementPart SubjectCapture(int capture_index) {
2520 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2521 }
2522 static inline ReplacementPart SubjectPrefix() {
2523 return ReplacementPart(SUBJECT_PREFIX, 0);
2524 }
2525 static inline ReplacementPart SubjectSuffix(int subject_length) {
2526 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2527 }
2528 static inline ReplacementPart ReplacementString() {
2529 return ReplacementPart(REPLACEMENT_STRING, 0);
2530 }
2531 static inline ReplacementPart ReplacementSubString(int from, int to) {
2532 ASSERT(from >= 0);
2533 ASSERT(to > from);
2534 return ReplacementPart(-from, to);
2535 }
2536
2537 // If tag <= 0 then it is the negation of a start index of a substring of
2538 // the replacement pattern, otherwise it's a value from PartType.
2539 ReplacementPart(int tag, int data)
2540 : tag(tag), data(data) {
2541 // Must be non-positive or a PartType value.
2542 ASSERT(tag < NUMBER_OF_PART_TYPES);
2543 }
2544 // Either a value of PartType or a non-positive number that is
2545 // the negation of an index into the replacement string.
2546 int tag;
2547 // The data value's interpretation depends on the value of tag:
2548 // tag == SUBJECT_PREFIX ||
2549 // tag == SUBJECT_SUFFIX: data is unused.
2550 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2551 // tag == REPLACEMENT_SUBSTRING ||
2552 // tag == REPLACEMENT_STRING: data is index into array of substrings
2553 // of the replacement string.
2554 // tag <= 0: Temporary representation of the substring of the replacement
2555 // string ranging over -tag .. data.
2556 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2557 // substring objects.
2558 int data;
2559 };
2560
2561 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002562 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002563 Vector<Char> characters,
2564 int capture_count,
2565 int subject_length) {
2566 int length = characters.length();
2567 int last = 0;
2568 for (int i = 0; i < length; i++) {
2569 Char c = characters[i];
2570 if (c == '$') {
2571 int next_index = i + 1;
2572 if (next_index == length) { // No next character!
2573 break;
2574 }
2575 Char c2 = characters[next_index];
2576 switch (c2) {
2577 case '$':
2578 if (i > last) {
2579 // There is a substring before. Include the first "$".
2580 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2581 last = next_index + 1; // Continue after the second "$".
2582 } else {
2583 // Let the next substring start with the second "$".
2584 last = next_index;
2585 }
2586 i = next_index;
2587 break;
2588 case '`':
2589 if (i > last) {
2590 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2591 }
2592 parts->Add(ReplacementPart::SubjectPrefix());
2593 i = next_index;
2594 last = i + 1;
2595 break;
2596 case '\'':
2597 if (i > last) {
2598 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2599 }
2600 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2601 i = next_index;
2602 last = i + 1;
2603 break;
2604 case '&':
2605 if (i > last) {
2606 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2607 }
2608 parts->Add(ReplacementPart::SubjectMatch());
2609 i = next_index;
2610 last = i + 1;
2611 break;
2612 case '0':
2613 case '1':
2614 case '2':
2615 case '3':
2616 case '4':
2617 case '5':
2618 case '6':
2619 case '7':
2620 case '8':
2621 case '9': {
2622 int capture_ref = c2 - '0';
2623 if (capture_ref > capture_count) {
2624 i = next_index;
2625 continue;
2626 }
2627 int second_digit_index = next_index + 1;
2628 if (second_digit_index < length) {
2629 // Peek ahead to see if we have two digits.
2630 Char c3 = characters[second_digit_index];
2631 if ('0' <= c3 && c3 <= '9') { // Double digits.
2632 int double_digit_ref = capture_ref * 10 + c3 - '0';
2633 if (double_digit_ref <= capture_count) {
2634 next_index = second_digit_index;
2635 capture_ref = double_digit_ref;
2636 }
2637 }
2638 }
2639 if (capture_ref > 0) {
2640 if (i > last) {
2641 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2642 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002643 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002644 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2645 last = next_index + 1;
2646 }
2647 i = next_index;
2648 break;
2649 }
2650 default:
2651 i = next_index;
2652 break;
2653 }
2654 }
2655 }
2656 if (length > last) {
2657 if (last == 0) {
2658 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002659 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002660 } else {
2661 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2662 }
2663 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002664 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002665 }
2666
2667 ZoneList<ReplacementPart> parts_;
2668 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002669 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002670};
2671
2672
2673void CompiledReplacement::Compile(Handle<String> replacement,
2674 int capture_count,
2675 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002676 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002677 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002678 String::FlatContent content = replacement->GetFlatContent();
2679 ASSERT(content.IsFlat());
2680 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002681 simple_hint_ = ParseReplacementPattern(&parts_,
2682 content.ToAsciiVector(),
2683 capture_count,
2684 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002685 } else {
2686 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002687 simple_hint_ = ParseReplacementPattern(&parts_,
2688 content.ToUC16Vector(),
2689 capture_count,
2690 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002691 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002692 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002693 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002694 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002695 int substring_index = 0;
2696 for (int i = 0, n = parts_.length(); i < n; i++) {
2697 int tag = parts_[i].tag;
2698 if (tag <= 0) { // A replacement string slice.
2699 int from = -tag;
2700 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002701 replacement_substrings_.Add(
2702 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002703 parts_[i].tag = REPLACEMENT_SUBSTRING;
2704 parts_[i].data = substring_index;
2705 substring_index++;
2706 } else if (tag == REPLACEMENT_STRING) {
2707 replacement_substrings_.Add(replacement);
2708 parts_[i].data = substring_index;
2709 substring_index++;
2710 }
2711 }
2712}
2713
2714
2715void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2716 int match_from,
2717 int match_to,
2718 Handle<JSArray> last_match_info) {
2719 for (int i = 0, n = parts_.length(); i < n; i++) {
2720 ReplacementPart part = parts_[i];
2721 switch (part.tag) {
2722 case SUBJECT_PREFIX:
2723 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2724 break;
2725 case SUBJECT_SUFFIX: {
2726 int subject_length = part.data;
2727 if (match_to < subject_length) {
2728 builder->AddSubjectSlice(match_to, subject_length);
2729 }
2730 break;
2731 }
2732 case SUBJECT_CAPTURE: {
2733 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002734 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002735 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2736 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2737 if (from >= 0 && to > from) {
2738 builder->AddSubjectSlice(from, to);
2739 }
2740 break;
2741 }
2742 case REPLACEMENT_SUBSTRING:
2743 case REPLACEMENT_STRING:
2744 builder->AddString(replacement_substrings_[part.data]);
2745 break;
2746 default:
2747 UNREACHABLE();
2748 }
2749 }
2750}
2751
2752
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002753void FindAsciiStringIndices(Vector<const char> subject,
2754 char pattern,
2755 ZoneList<int>* indices,
2756 unsigned int limit) {
2757 ASSERT(limit > 0);
2758 // Collect indices of pattern in subject using memchr.
2759 // Stop after finding at most limit values.
2760 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2761 const char* subject_end = subject_start + subject.length();
2762 const char* pos = subject_start;
2763 while (limit > 0) {
2764 pos = reinterpret_cast<const char*>(
2765 memchr(pos, pattern, subject_end - pos));
2766 if (pos == NULL) return;
2767 indices->Add(static_cast<int>(pos - subject_start));
2768 pos++;
2769 limit--;
2770 }
2771}
2772
2773
2774template <typename SubjectChar, typename PatternChar>
2775void FindStringIndices(Isolate* isolate,
2776 Vector<const SubjectChar> subject,
2777 Vector<const PatternChar> pattern,
2778 ZoneList<int>* indices,
2779 unsigned int limit) {
2780 ASSERT(limit > 0);
2781 // Collect indices of pattern in subject.
2782 // Stop after finding at most limit values.
2783 int pattern_length = pattern.length();
2784 int index = 0;
2785 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2786 while (limit > 0) {
2787 index = search.Search(subject, index);
2788 if (index < 0) return;
2789 indices->Add(index);
2790 index += pattern_length;
2791 limit--;
2792 }
2793}
2794
2795
2796void FindStringIndicesDispatch(Isolate* isolate,
2797 String* subject,
2798 String* pattern,
2799 ZoneList<int>* indices,
2800 unsigned int limit) {
2801 {
2802 AssertNoAllocation no_gc;
2803 String::FlatContent subject_content = subject->GetFlatContent();
2804 String::FlatContent pattern_content = pattern->GetFlatContent();
2805 ASSERT(subject_content.IsFlat());
2806 ASSERT(pattern_content.IsFlat());
2807 if (subject_content.IsAscii()) {
2808 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2809 if (pattern_content.IsAscii()) {
2810 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2811 if (pattern_vector.length() == 1) {
2812 FindAsciiStringIndices(subject_vector,
2813 pattern_vector[0],
2814 indices,
2815 limit);
2816 } else {
2817 FindStringIndices(isolate,
2818 subject_vector,
2819 pattern_vector,
2820 indices,
2821 limit);
2822 }
2823 } else {
2824 FindStringIndices(isolate,
2825 subject_vector,
2826 pattern_content.ToUC16Vector(),
2827 indices,
2828 limit);
2829 }
2830 } else {
2831 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002832 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002833 FindStringIndices(isolate,
2834 subject_vector,
2835 pattern_content.ToAsciiVector(),
2836 indices,
2837 limit);
2838 } else {
2839 FindStringIndices(isolate,
2840 subject_vector,
2841 pattern_content.ToUC16Vector(),
2842 indices,
2843 limit);
2844 }
2845 }
2846 }
2847}
2848
2849
2850template<typename ResultSeqString>
2851MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2852 Isolate* isolate,
2853 Handle<String> subject,
2854 Handle<JSRegExp> pattern_regexp,
2855 Handle<String> replacement) {
2856 ASSERT(subject->IsFlat());
2857 ASSERT(replacement->IsFlat());
2858
2859 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2860 ZoneList<int> indices(8);
2861 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2862 String* pattern =
2863 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2864 int subject_len = subject->length();
2865 int pattern_len = pattern->length();
2866 int replacement_len = replacement->length();
2867
2868 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2869
2870 int matches = indices.length();
2871 if (matches == 0) return *subject;
2872
2873 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2874 int subject_pos = 0;
2875 int result_pos = 0;
2876
2877 Handle<ResultSeqString> result;
2878 if (ResultSeqString::kHasAsciiEncoding) {
2879 result = Handle<ResultSeqString>::cast(
2880 isolate->factory()->NewRawAsciiString(result_len));
2881 } else {
2882 result = Handle<ResultSeqString>::cast(
2883 isolate->factory()->NewRawTwoByteString(result_len));
2884 }
2885
2886 for (int i = 0; i < matches; i++) {
2887 // Copy non-matched subject content.
2888 if (subject_pos < indices.at(i)) {
2889 String::WriteToFlat(*subject,
2890 result->GetChars() + result_pos,
2891 subject_pos,
2892 indices.at(i));
2893 result_pos += indices.at(i) - subject_pos;
2894 }
2895
2896 // Replace match.
2897 if (replacement_len > 0) {
2898 String::WriteToFlat(*replacement,
2899 result->GetChars() + result_pos,
2900 0,
2901 replacement_len);
2902 result_pos += replacement_len;
2903 }
2904
2905 subject_pos = indices.at(i) + pattern_len;
2906 }
2907 // Add remaining subject content at the end.
2908 if (subject_pos < subject_len) {
2909 String::WriteToFlat(*subject,
2910 result->GetChars() + result_pos,
2911 subject_pos,
2912 subject_len);
2913 }
2914 return *result;
2915}
2916
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002917
lrn@chromium.org303ada72010-10-27 09:33:13 +00002918MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002919 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002920 String* subject,
2921 JSRegExp* regexp,
2922 String* replacement,
2923 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002924 ASSERT(subject->IsFlat());
2925 ASSERT(replacement->IsFlat());
2926
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002927 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002928
2929 int length = subject->length();
2930 Handle<String> subject_handle(subject);
2931 Handle<JSRegExp> regexp_handle(regexp);
2932 Handle<String> replacement_handle(replacement);
2933 Handle<JSArray> last_match_info_handle(last_match_info);
2934 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2935 subject_handle,
2936 0,
2937 last_match_info_handle);
2938 if (match.is_null()) {
2939 return Failure::Exception();
2940 }
2941 if (match->IsNull()) {
2942 return *subject_handle;
2943 }
2944
2945 int capture_count = regexp_handle->CaptureCount();
2946
2947 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002948 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002949 CompiledReplacement compiled_replacement;
2950 compiled_replacement.Compile(replacement_handle,
2951 capture_count,
2952 length);
2953
2954 bool is_global = regexp_handle->GetFlags().is_global();
2955
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002956 // Shortcut for simple non-regexp global replacements
2957 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002958 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002959 compiled_replacement.simple_hint()) {
2960 if (subject_handle->HasOnlyAsciiChars() &&
2961 replacement_handle->HasOnlyAsciiChars()) {
2962 return StringReplaceStringWithString<SeqAsciiString>(
2963 isolate, subject_handle, regexp_handle, replacement_handle);
2964 } else {
2965 return StringReplaceStringWithString<SeqTwoByteString>(
2966 isolate, subject_handle, regexp_handle, replacement_handle);
2967 }
2968 }
2969
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002970 // Guessing the number of parts that the final result string is built
2971 // from. Global regexps can match any number of times, so we guess
2972 // conservatively.
2973 int expected_parts =
2974 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002975 ReplacementStringBuilder builder(isolate->heap(),
2976 subject_handle,
2977 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002978
2979 // Index of end of last match.
2980 int prev = 0;
2981
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002982 // Number of parts added by compiled replacement plus preceeding
2983 // string and possibly suffix after last match. It is possible for
2984 // all components to use two elements when encoded as two smis.
2985 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002986 bool matched = true;
2987 do {
2988 ASSERT(last_match_info_handle->HasFastElements());
2989 // Increase the capacity of the builder before entering local handle-scope,
2990 // so its internal buffer can safely allocate a new handle if it grows.
2991 builder.EnsureCapacity(parts_added_per_loop);
2992
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002993 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002994 int start, end;
2995 {
2996 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002997 FixedArray* match_info_array =
2998 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002999
3000 ASSERT_EQ(capture_count * 2 + 2,
3001 RegExpImpl::GetLastCaptureCount(match_info_array));
3002 start = RegExpImpl::GetCapture(match_info_array, 0);
3003 end = RegExpImpl::GetCapture(match_info_array, 1);
3004 }
3005
3006 if (prev < start) {
3007 builder.AddSubjectSlice(prev, start);
3008 }
3009 compiled_replacement.Apply(&builder,
3010 start,
3011 end,
3012 last_match_info_handle);
3013 prev = end;
3014
3015 // Only continue checking for global regexps.
3016 if (!is_global) break;
3017
3018 // Continue from where the match ended, unless it was an empty match.
3019 int next = end;
3020 if (start == end) {
3021 next = end + 1;
3022 if (next > length) break;
3023 }
3024
3025 match = RegExpImpl::Exec(regexp_handle,
3026 subject_handle,
3027 next,
3028 last_match_info_handle);
3029 if (match.is_null()) {
3030 return Failure::Exception();
3031 }
3032 matched = !match->IsNull();
3033 } while (matched);
3034
3035 if (prev < length) {
3036 builder.AddSubjectSlice(prev, length);
3037 }
3038
3039 return *(builder.ToString());
3040}
3041
3042
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003043template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003044MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003045 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003046 String* subject,
3047 JSRegExp* regexp,
3048 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003049 ASSERT(subject->IsFlat());
3050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003051 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003052
3053 Handle<String> subject_handle(subject);
3054 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003055
3056 // Shortcut for simple non-regexp global replacements
3057 if (regexp_handle->GetFlags().is_global() &&
3058 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3059 Handle<String> empty_string_handle(HEAP->empty_string());
3060 if (subject_handle->HasOnlyAsciiChars()) {
3061 return StringReplaceStringWithString<SeqAsciiString>(
3062 isolate, subject_handle, regexp_handle, empty_string_handle);
3063 } else {
3064 return StringReplaceStringWithString<SeqTwoByteString>(
3065 isolate, subject_handle, regexp_handle, empty_string_handle);
3066 }
3067 }
3068
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003069 Handle<JSArray> last_match_info_handle(last_match_info);
3070 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3071 subject_handle,
3072 0,
3073 last_match_info_handle);
3074 if (match.is_null()) return Failure::Exception();
3075 if (match->IsNull()) return *subject_handle;
3076
3077 ASSERT(last_match_info_handle->HasFastElements());
3078
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003079 int start, end;
3080 {
3081 AssertNoAllocation match_info_array_is_not_in_a_handle;
3082 FixedArray* match_info_array =
3083 FixedArray::cast(last_match_info_handle->elements());
3084
3085 start = RegExpImpl::GetCapture(match_info_array, 0);
3086 end = RegExpImpl::GetCapture(match_info_array, 1);
3087 }
3088
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003089 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003090 int new_length = length - (end - start);
3091 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003092 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003093 }
3094 Handle<ResultSeqString> answer;
3095 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003096 answer = Handle<ResultSeqString>::cast(
3097 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003098 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003099 answer = Handle<ResultSeqString>::cast(
3100 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003101 }
3102
3103 // If the regexp isn't global, only match once.
3104 if (!regexp_handle->GetFlags().is_global()) {
3105 if (start > 0) {
3106 String::WriteToFlat(*subject_handle,
3107 answer->GetChars(),
3108 0,
3109 start);
3110 }
3111 if (end < length) {
3112 String::WriteToFlat(*subject_handle,
3113 answer->GetChars() + start,
3114 end,
3115 length);
3116 }
3117 return *answer;
3118 }
3119
3120 int prev = 0; // Index of end of last match.
3121 int next = 0; // Start of next search (prev unless last match was empty).
3122 int position = 0;
3123
3124 do {
3125 if (prev < start) {
3126 // Add substring subject[prev;start] to answer string.
3127 String::WriteToFlat(*subject_handle,
3128 answer->GetChars() + position,
3129 prev,
3130 start);
3131 position += start - prev;
3132 }
3133 prev = end;
3134 next = end;
3135 // Continue from where the match ended, unless it was an empty match.
3136 if (start == end) {
3137 next++;
3138 if (next > length) break;
3139 }
3140 match = RegExpImpl::Exec(regexp_handle,
3141 subject_handle,
3142 next,
3143 last_match_info_handle);
3144 if (match.is_null()) return Failure::Exception();
3145 if (match->IsNull()) break;
3146
3147 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003148 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003149 {
3150 AssertNoAllocation match_info_array_is_not_in_a_handle;
3151 FixedArray* match_info_array =
3152 FixedArray::cast(last_match_info_handle->elements());
3153 start = RegExpImpl::GetCapture(match_info_array, 0);
3154 end = RegExpImpl::GetCapture(match_info_array, 1);
3155 }
3156 } while (true);
3157
3158 if (prev < length) {
3159 // Add substring subject[prev;length] to answer string.
3160 String::WriteToFlat(*subject_handle,
3161 answer->GetChars() + position,
3162 prev,
3163 length);
3164 position += length - prev;
3165 }
3166
3167 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003168 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003169 }
3170
3171 // Shorten string and fill
3172 int string_size = ResultSeqString::SizeFor(position);
3173 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3174 int delta = allocated_string_size - string_size;
3175
3176 answer->set_length(position);
3177 if (delta == 0) return *answer;
3178
3179 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003180 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003181 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3182 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3183 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003184
3185 return *answer;
3186}
3187
3188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003189RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003190 ASSERT(args.length() == 4);
3191
3192 CONVERT_CHECKED(String, subject, args[0]);
3193 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003194 Object* flat_subject;
3195 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3196 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3197 return maybe_flat_subject;
3198 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003199 }
3200 subject = String::cast(flat_subject);
3201 }
3202
3203 CONVERT_CHECKED(String, replacement, args[2]);
3204 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003205 Object* flat_replacement;
3206 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3207 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3208 return maybe_flat_replacement;
3209 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003210 }
3211 replacement = String::cast(flat_replacement);
3212 }
3213
3214 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3215 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3216
3217 ASSERT(last_match_info->HasFastElements());
3218
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003219 if (replacement->length() == 0) {
3220 if (subject->HasOnlyAsciiChars()) {
3221 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003222 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003223 } else {
3224 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003225 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003226 }
3227 }
3228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003229 return StringReplaceRegExpWithString(isolate,
3230 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003231 regexp,
3232 replacement,
3233 last_match_info);
3234}
3235
3236
ager@chromium.org7c537e22008-10-16 08:43:32 +00003237// Perform string match of pattern on subject, starting at start index.
3238// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003239// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003240int Runtime::StringMatch(Isolate* isolate,
3241 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003242 Handle<String> pat,
3243 int start_index) {
3244 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003245 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003246
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003247 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003248 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003249
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003250 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003251 if (start_index + pattern_length > subject_length) return -1;
3252
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003253 if (!sub->IsFlat()) FlattenString(sub);
3254 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003255
ager@chromium.org7c537e22008-10-16 08:43:32 +00003256 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003257 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003258 String::FlatContent seq_sub = sub->GetFlatContent();
3259 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003260
ager@chromium.org7c537e22008-10-16 08:43:32 +00003261 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003262 if (seq_pat.IsAscii()) {
3263 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3264 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003265 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003266 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003267 pat_vector,
3268 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003269 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003270 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003271 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003272 pat_vector,
3273 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003274 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003275 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3276 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003277 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003278 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003279 pat_vector,
3280 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003281 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003282 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003283 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003284 pat_vector,
3285 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003286}
3287
3288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003289RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003290 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003291 ASSERT(args.length() == 3);
3292
ager@chromium.org7c537e22008-10-16 08:43:32 +00003293 CONVERT_ARG_CHECKED(String, sub, 0);
3294 CONVERT_ARG_CHECKED(String, pat, 1);
3295
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003296 Object* index = args[2];
3297 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003298 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003299
ager@chromium.org870a0b62008-11-04 11:43:05 +00003300 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003301 int position =
3302 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003303 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003304}
3305
3306
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003307template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003308static int StringMatchBackwards(Vector<const schar> subject,
3309 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003310 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003311 int pattern_length = pattern.length();
3312 ASSERT(pattern_length >= 1);
3313 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003314
3315 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003316 for (int i = 0; i < pattern_length; i++) {
3317 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003318 if (c > String::kMaxAsciiCharCode) {
3319 return -1;
3320 }
3321 }
3322 }
3323
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003324 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003325 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003326 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003327 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003328 while (j < pattern_length) {
3329 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003330 break;
3331 }
3332 j++;
3333 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003334 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003335 return i;
3336 }
3337 }
3338 return -1;
3339}
3340
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003341RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003342 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003343 ASSERT(args.length() == 3);
3344
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003345 CONVERT_ARG_CHECKED(String, sub, 0);
3346 CONVERT_ARG_CHECKED(String, pat, 1);
3347
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003348 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003349 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003350 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003351
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003352 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003353 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003354
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003355 if (start_index + pat_length > sub_length) {
3356 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003357 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003358
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003359 if (pat_length == 0) {
3360 return Smi::FromInt(start_index);
3361 }
3362
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003363 if (!sub->IsFlat()) FlattenString(sub);
3364 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003365
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003366 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003367 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3368
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003369 String::FlatContent sub_content = sub->GetFlatContent();
3370 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003371
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003372 if (pat_content.IsAscii()) {
3373 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3374 if (sub_content.IsAscii()) {
3375 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003376 pat_vector,
3377 start_index);
3378 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003379 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003380 pat_vector,
3381 start_index);
3382 }
3383 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003384 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3385 if (sub_content.IsAscii()) {
3386 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003387 pat_vector,
3388 start_index);
3389 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003390 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003391 pat_vector,
3392 start_index);
3393 }
3394 }
3395
3396 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003397}
3398
3399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003400RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 NoHandleAllocation ha;
3402 ASSERT(args.length() == 2);
3403
3404 CONVERT_CHECKED(String, str1, args[0]);
3405 CONVERT_CHECKED(String, str2, args[1]);
3406
3407 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003408 int str1_length = str1->length();
3409 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410
3411 // Decide trivial cases without flattening.
3412 if (str1_length == 0) {
3413 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3414 return Smi::FromInt(-str2_length);
3415 } else {
3416 if (str2_length == 0) return Smi::FromInt(str1_length);
3417 }
3418
3419 int end = str1_length < str2_length ? str1_length : str2_length;
3420
3421 // No need to flatten if we are going to find the answer on the first
3422 // character. At this point we know there is at least one character
3423 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003424 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003425 if (d != 0) return Smi::FromInt(d);
3426
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003427 str1->TryFlatten();
3428 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003430 StringInputBuffer& buf1 =
3431 *isolate->runtime_state()->string_locale_compare_buf1();
3432 StringInputBuffer& buf2 =
3433 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003434
3435 buf1.Reset(str1);
3436 buf2.Reset(str2);
3437
3438 for (int i = 0; i < end; i++) {
3439 uint16_t char1 = buf1.GetNext();
3440 uint16_t char2 = buf2.GetNext();
3441 if (char1 != char2) return Smi::FromInt(char1 - char2);
3442 }
3443
3444 return Smi::FromInt(str1_length - str2_length);
3445}
3446
3447
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003448RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003449 NoHandleAllocation ha;
3450 ASSERT(args.length() == 3);
3451
3452 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003453 int start, end;
3454 // We have a fast integer-only case here to avoid a conversion to double in
3455 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003456 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3457 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3458 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3459 start = from_number;
3460 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003461 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003462 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3463 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003464 start = FastD2I(from_number);
3465 end = FastD2I(to_number);
3466 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003467 RUNTIME_ASSERT(end >= start);
3468 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003469 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003470 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003471 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472}
3473
3474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003475RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003476 ASSERT_EQ(3, args.length());
3477
3478 CONVERT_ARG_CHECKED(String, subject, 0);
3479 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3480 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3481 HandleScope handles;
3482
3483 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3484
3485 if (match.is_null()) {
3486 return Failure::Exception();
3487 }
3488 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003489 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003490 }
3491 int length = subject->length();
3492
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003493 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003494 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003495 int start;
3496 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003497 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003498 {
3499 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003500 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003501 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3502 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3503 }
3504 offsets.Add(start);
3505 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003506 if (start == end) if (++end > length) break;
3507 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003508 if (match.is_null()) {
3509 return Failure::Exception();
3510 }
3511 } while (!match->IsNull());
3512 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003513 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003514 Handle<String> substring = isolate->factory()->
3515 NewSubString(subject, offsets.at(0), offsets.at(1));
3516 elements->set(0, *substring);
3517 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003518 int from = offsets.at(i * 2);
3519 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003520 Handle<String> substring = isolate->factory()->
3521 NewProperSubString(subject, from, to);
3522 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003523 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003524 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003525 result->set_length(Smi::FromInt(matches));
3526 return *result;
3527}
3528
3529
lrn@chromium.org25156de2010-04-06 13:10:27 +00003530// Two smis before and after the match, for very long strings.
3531const int kMaxBuilderEntriesPerRegExpMatch = 5;
3532
3533
3534static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3535 Handle<JSArray> last_match_info,
3536 int match_start,
3537 int match_end) {
3538 // Fill last_match_info with a single capture.
3539 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3540 AssertNoAllocation no_gc;
3541 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3542 RegExpImpl::SetLastCaptureCount(elements, 2);
3543 RegExpImpl::SetLastInput(elements, *subject);
3544 RegExpImpl::SetLastSubject(elements, *subject);
3545 RegExpImpl::SetCapture(elements, 0, match_start);
3546 RegExpImpl::SetCapture(elements, 1, match_end);
3547}
3548
3549
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003550template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003551static bool SearchStringMultiple(Isolate* isolate,
3552 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003553 Vector<const PatternChar> pattern,
3554 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003555 FixedArrayBuilder* builder,
3556 int* match_pos) {
3557 int pos = *match_pos;
3558 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003559 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003560 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003561 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003562 while (pos <= max_search_start) {
3563 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3564 *match_pos = pos;
3565 return false;
3566 }
3567 // Position of end of previous match.
3568 int match_end = pos + pattern_length;
3569 int new_pos = search.Search(subject, match_end);
3570 if (new_pos >= 0) {
3571 // A match.
3572 if (new_pos > match_end) {
3573 ReplacementStringBuilder::AddSubjectSlice(builder,
3574 match_end,
3575 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003576 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003577 pos = new_pos;
3578 builder->Add(pattern_string);
3579 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003580 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003581 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003582 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003583
lrn@chromium.org25156de2010-04-06 13:10:27 +00003584 if (pos < max_search_start) {
3585 ReplacementStringBuilder::AddSubjectSlice(builder,
3586 pos + pattern_length,
3587 subject_length);
3588 }
3589 *match_pos = pos;
3590 return true;
3591}
3592
3593
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594static bool SearchStringMultiple(Isolate* isolate,
3595 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003596 Handle<String> pattern,
3597 Handle<JSArray> last_match_info,
3598 FixedArrayBuilder* builder) {
3599 ASSERT(subject->IsFlat());
3600 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003601
3602 // Treating as if a previous match was before first character.
3603 int match_pos = -pattern->length();
3604
3605 for (;;) { // Break when search complete.
3606 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3607 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003608 String::FlatContent subject_content = subject->GetFlatContent();
3609 String::FlatContent pattern_content = pattern->GetFlatContent();
3610 if (subject_content.IsAscii()) {
3611 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3612 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003613 if (SearchStringMultiple(isolate,
3614 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003615 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003616 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003617 builder,
3618 &match_pos)) break;
3619 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003620 if (SearchStringMultiple(isolate,
3621 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003622 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003623 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003624 builder,
3625 &match_pos)) break;
3626 }
3627 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003628 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3629 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003630 if (SearchStringMultiple(isolate,
3631 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003632 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003633 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003634 builder,
3635 &match_pos)) break;
3636 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003637 if (SearchStringMultiple(isolate,
3638 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003639 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003640 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003641 builder,
3642 &match_pos)) break;
3643 }
3644 }
3645 }
3646
3647 if (match_pos >= 0) {
3648 SetLastMatchInfoNoCaptures(subject,
3649 last_match_info,
3650 match_pos,
3651 match_pos + pattern->length());
3652 return true;
3653 }
3654 return false; // No matches at all.
3655}
3656
3657
3658static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003659 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003660 Handle<String> subject,
3661 Handle<JSRegExp> regexp,
3662 Handle<JSArray> last_match_array,
3663 FixedArrayBuilder* builder) {
3664 ASSERT(subject->IsFlat());
3665 int match_start = -1;
3666 int match_end = 0;
3667 int pos = 0;
3668 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3669 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3670
3671 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003672 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003673 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003674 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003675
3676 for (;;) { // Break on failure, return on exception.
3677 RegExpImpl::IrregexpResult result =
3678 RegExpImpl::IrregexpExecOnce(regexp,
3679 subject,
3680 pos,
3681 register_vector);
3682 if (result == RegExpImpl::RE_SUCCESS) {
3683 match_start = register_vector[0];
3684 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3685 if (match_end < match_start) {
3686 ReplacementStringBuilder::AddSubjectSlice(builder,
3687 match_end,
3688 match_start);
3689 }
3690 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003691 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003692 if (!first) {
3693 builder->Add(*isolate->factory()->NewProperSubString(subject,
3694 match_start,
3695 match_end));
3696 } else {
3697 builder->Add(*isolate->factory()->NewSubString(subject,
3698 match_start,
3699 match_end));
3700 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003701 if (match_start != match_end) {
3702 pos = match_end;
3703 } else {
3704 pos = match_end + 1;
3705 if (pos > subject_length) break;
3706 }
3707 } else if (result == RegExpImpl::RE_FAILURE) {
3708 break;
3709 } else {
3710 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3711 return result;
3712 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003713 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003714 }
3715
3716 if (match_start >= 0) {
3717 if (match_end < subject_length) {
3718 ReplacementStringBuilder::AddSubjectSlice(builder,
3719 match_end,
3720 subject_length);
3721 }
3722 SetLastMatchInfoNoCaptures(subject,
3723 last_match_array,
3724 match_start,
3725 match_end);
3726 return RegExpImpl::RE_SUCCESS;
3727 } else {
3728 return RegExpImpl::RE_FAILURE; // No matches at all.
3729 }
3730}
3731
3732
3733static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003734 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003735 Handle<String> subject,
3736 Handle<JSRegExp> regexp,
3737 Handle<JSArray> last_match_array,
3738 FixedArrayBuilder* builder) {
3739
3740 ASSERT(subject->IsFlat());
3741 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3742 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3743
3744 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003745 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003746
3747 RegExpImpl::IrregexpResult result =
3748 RegExpImpl::IrregexpExecOnce(regexp,
3749 subject,
3750 0,
3751 register_vector);
3752
3753 int capture_count = regexp->CaptureCount();
3754 int subject_length = subject->length();
3755
3756 // Position to search from.
3757 int pos = 0;
3758 // End of previous match. Differs from pos if match was empty.
3759 int match_end = 0;
3760 if (result == RegExpImpl::RE_SUCCESS) {
3761 // Need to keep a copy of the previous match for creating last_match_info
3762 // at the end, so we have two vectors that we swap between.
3763 OffsetsVector registers2(required_registers);
3764 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003765 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003766 do {
3767 int match_start = register_vector[0];
3768 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3769 if (match_end < match_start) {
3770 ReplacementStringBuilder::AddSubjectSlice(builder,
3771 match_end,
3772 match_start);
3773 }
3774 match_end = register_vector[1];
3775
3776 {
3777 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003778 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003779 // Arguments array to replace function is match, captures, index and
3780 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003781 Handle<FixedArray> elements =
3782 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003783 Handle<String> match;
3784 if (!first) {
3785 match = isolate->factory()->NewProperSubString(subject,
3786 match_start,
3787 match_end);
3788 } else {
3789 match = isolate->factory()->NewSubString(subject,
3790 match_start,
3791 match_end);
3792 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003793 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003794 for (int i = 1; i <= capture_count; i++) {
3795 int start = register_vector[i * 2];
3796 if (start >= 0) {
3797 int end = register_vector[i * 2 + 1];
3798 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003799 Handle<String> substring;
3800 if (!first) {
3801 substring = isolate->factory()->NewProperSubString(subject,
3802 start,
3803 end);
3804 } else {
3805 substring = isolate->factory()->NewSubString(subject, start, end);
3806 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003807 elements->set(i, *substring);
3808 } else {
3809 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003810 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003811 }
3812 }
3813 elements->set(capture_count + 1, Smi::FromInt(match_start));
3814 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003815 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003816 }
3817 // Swap register vectors, so the last successful match is in
3818 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003819 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003820 prev_register_vector = register_vector;
3821 register_vector = tmp;
3822
3823 if (match_end > match_start) {
3824 pos = match_end;
3825 } else {
3826 pos = match_end + 1;
3827 if (pos > subject_length) {
3828 break;
3829 }
3830 }
3831
3832 result = RegExpImpl::IrregexpExecOnce(regexp,
3833 subject,
3834 pos,
3835 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003836 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003837 } while (result == RegExpImpl::RE_SUCCESS);
3838
3839 if (result != RegExpImpl::RE_EXCEPTION) {
3840 // Finished matching, with at least one match.
3841 if (match_end < subject_length) {
3842 ReplacementStringBuilder::AddSubjectSlice(builder,
3843 match_end,
3844 subject_length);
3845 }
3846
3847 int last_match_capture_count = (capture_count + 1) * 2;
3848 int last_match_array_size =
3849 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3850 last_match_array->EnsureSize(last_match_array_size);
3851 AssertNoAllocation no_gc;
3852 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3853 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3854 RegExpImpl::SetLastSubject(elements, *subject);
3855 RegExpImpl::SetLastInput(elements, *subject);
3856 for (int i = 0; i < last_match_capture_count; i++) {
3857 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3858 }
3859 return RegExpImpl::RE_SUCCESS;
3860 }
3861 }
3862 // No matches at all, return failure or exception result directly.
3863 return result;
3864}
3865
3866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003867RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003868 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003869 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003870
3871 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003872 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003873 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3874 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3875 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3876
3877 ASSERT(last_match_info->HasFastElements());
3878 ASSERT(regexp->GetFlags().is_global());
3879 Handle<FixedArray> result_elements;
3880 if (result_array->HasFastElements()) {
3881 result_elements =
3882 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003883 }
3884 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003885 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003886 }
3887 FixedArrayBuilder builder(result_elements);
3888
3889 if (regexp->TypeTag() == JSRegExp::ATOM) {
3890 Handle<String> pattern(
3891 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003892 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003893 if (SearchStringMultiple(isolate, subject, pattern,
3894 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003895 return *builder.ToJSArray(result_array);
3896 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003897 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003898 }
3899
3900 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3901
3902 RegExpImpl::IrregexpResult result;
3903 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003904 result = SearchRegExpNoCaptureMultiple(isolate,
3905 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003906 regexp,
3907 last_match_info,
3908 &builder);
3909 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003910 result = SearchRegExpMultiple(isolate,
3911 subject,
3912 regexp,
3913 last_match_info,
3914 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003915 }
3916 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003917 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003918 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3919 return Failure::Exception();
3920}
3921
3922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003923RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003924 NoHandleAllocation ha;
3925 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003926 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003927 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003929 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003930 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003931 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003932 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003933 // Character array used for conversion.
3934 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003935 return isolate->heap()->
3936 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003937 }
3938 }
3939
3940 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003941 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003942 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003943 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944 }
3945 if (isinf(value)) {
3946 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003947 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003949 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003950 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003951 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003952 MaybeObject* result =
3953 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003954 DeleteArray(str);
3955 return result;
3956}
3957
3958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003959RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003960 NoHandleAllocation ha;
3961 ASSERT(args.length() == 2);
3962
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003963 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003964 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003965 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003966 }
3967 if (isinf(value)) {
3968 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003969 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003971 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003973 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 int f = FastD2I(f_number);
3975 RUNTIME_ASSERT(f >= 0);
3976 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003977 MaybeObject* res =
3978 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003980 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003981}
3982
3983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003984RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 NoHandleAllocation ha;
3986 ASSERT(args.length() == 2);
3987
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003988 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003989 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003990 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003991 }
3992 if (isinf(value)) {
3993 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003994 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003995 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003996 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003997 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003998 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003999 int f = FastD2I(f_number);
4000 RUNTIME_ASSERT(f >= -1 && f <= 20);
4001 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004002 MaybeObject* res =
4003 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004005 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004006}
4007
4008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004009RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010 NoHandleAllocation ha;
4011 ASSERT(args.length() == 2);
4012
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004013 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004015 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 }
4017 if (isinf(value)) {
4018 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004019 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004021 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004023 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024 int f = FastD2I(f_number);
4025 RUNTIME_ASSERT(f >= 1 && f <= 21);
4026 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004027 MaybeObject* res =
4028 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004030 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004031}
4032
4033
4034// Returns a single character string where first character equals
4035// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004036static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004037 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004038 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004039 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004040 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004041 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004042 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004043}
4044
4045
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004046MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4047 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004048 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004049 // Handle [] indexing on Strings
4050 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004051 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4052 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 }
4054
4055 // Handle [] indexing on String objects
4056 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004057 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4058 Handle<Object> result =
4059 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4060 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004061 }
4062
4063 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004064 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 return prototype->GetElement(index);
4066 }
4067
4068 return object->GetElement(index);
4069}
4070
4071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004072MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4073 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004074 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004075 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004076
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004078 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004080 isolate->factory()->NewTypeError("non_object_property_load",
4081 HandleVector(args, 2));
4082 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004083 }
4084
4085 // Check if the given key is an array index.
4086 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004087 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004088 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004089 }
4090
4091 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004092 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004094 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004095 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 bool has_pending_exception = false;
4097 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004098 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004100 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 }
4102
ager@chromium.org32912102009-01-16 10:38:43 +00004103 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004104 // the element if so.
4105 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004106 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004108 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 }
4110}
4111
4112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004113RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 NoHandleAllocation ha;
4115 ASSERT(args.length() == 2);
4116
4117 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004118 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004120 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004121}
4122
4123
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004124MaybeObject* TransitionElements(Handle<Object> object,
4125 ElementsKind to_kind,
4126 Isolate* isolate) {
4127 HandleScope scope(isolate);
4128 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4129 ElementsKind from_kind =
4130 Handle<JSObject>::cast(object)->map()->elements_kind();
4131 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
4132 Handle<Object> result =
4133 TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
4134 if (result.is_null()) return isolate->ThrowIllegalOperation();
4135 return *result;
4136 }
4137 return isolate->ThrowIllegalOperation();
4138}
4139
4140
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004141// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004142RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004143 NoHandleAllocation ha;
4144 ASSERT(args.length() == 2);
4145
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004146 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004147 // itself.
4148 //
4149 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004150 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004151 // global proxy object never has properties. This is the case
4152 // because the global proxy object forwards everything to its hidden
4153 // prototype including local lookups.
4154 //
4155 // Additionally, we need to make sure that we do not cache results
4156 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004157 if (args[0]->IsJSObject()) {
4158 if (!args[0]->IsJSGlobalProxy() &&
4159 !args[0]->IsAccessCheckNeeded() &&
4160 args[1]->IsString()) {
4161 JSObject* receiver = JSObject::cast(args[0]);
4162 String* key = String::cast(args[1]);
4163 if (receiver->HasFastProperties()) {
4164 // Attempt to use lookup cache.
4165 Map* receiver_map = receiver->map();
4166 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4167 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4168 if (offset != -1) {
4169 Object* value = receiver->FastPropertyAt(offset);
4170 return value->IsTheHole()
4171 ? isolate->heap()->undefined_value()
4172 : value;
4173 }
4174 // Lookup cache miss. Perform lookup and update the cache if
4175 // appropriate.
4176 LookupResult result(isolate);
4177 receiver->LocalLookup(key, &result);
4178 if (result.IsProperty() && result.type() == FIELD) {
4179 int offset = result.GetFieldIndex();
4180 keyed_lookup_cache->Update(receiver_map, key, offset);
4181 return receiver->FastPropertyAt(offset);
4182 }
4183 } else {
4184 // Attempt dictionary lookup.
4185 StringDictionary* dictionary = receiver->property_dictionary();
4186 int entry = dictionary->FindEntry(key);
4187 if ((entry != StringDictionary::kNotFound) &&
4188 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4189 Object* value = dictionary->ValueAt(entry);
4190 if (!receiver->IsGlobalObject()) return value;
4191 value = JSGlobalPropertyCell::cast(value)->value();
4192 if (!value->IsTheHole()) return value;
4193 // If value is the hole do the general lookup.
4194 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004195 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004196 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4197 // JSObject without a string key. If the key is a Smi, check for a
4198 // definite out-of-bounds access to elements, which is a strong indicator
4199 // that subsequent accesses will also call the runtime. Proactively
4200 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4201 // doubles for those future calls in the case that the elements would
4202 // become FAST_DOUBLE_ELEMENTS.
4203 Handle<JSObject> js_object(args.at<JSObject>(0));
4204 ElementsKind elements_kind = js_object->GetElementsKind();
4205 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4206 elements_kind == FAST_DOUBLE_ELEMENTS) {
4207 FixedArrayBase* elements = js_object->elements();
4208 if (args.at<Smi>(1)->value() >= elements->length()) {
4209 MaybeObject* maybe_object = TransitionElements(js_object,
4210 FAST_ELEMENTS,
4211 isolate);
4212 if (maybe_object->IsFailure()) return maybe_object;
4213 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004214 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004215 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004216 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4217 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004218 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004219 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004220 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004221 if (index >= 0 && index < str->length()) {
4222 Handle<Object> result = GetCharAt(str, index);
4223 return *result;
4224 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004225 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004226
4227 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004228 return Runtime::GetObjectProperty(isolate,
4229 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004230 args.at<Object>(1));
4231}
4232
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004233// Implements part of 8.12.9 DefineOwnProperty.
4234// There are 3 cases that lead here:
4235// Step 4b - define a new accessor property.
4236// Steps 9c & 12 - replace an existing data property with an accessor property.
4237// Step 12 - update an existing accessor property with an accessor or generic
4238// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004239RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004240 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004241 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004242 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4243 CONVERT_CHECKED(String, name, args[1]);
4244 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004245 Object* fun = args[3];
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004246 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004247 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4248 int unchecked = flag_attr->value();
4249 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4250 RUNTIME_ASSERT(!obj->IsNull());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004251 LookupResult result(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004252 obj->LocalLookupRealNamedProperty(name, &result);
4253
4254 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4255 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4256 // delete it to avoid running into trouble in DefineAccessor, which
4257 // handles this incorrectly if the property is readonly (does nothing)
4258 if (result.IsProperty() &&
4259 (result.type() == FIELD || result.type() == NORMAL
4260 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004261 Object* ok;
4262 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004263 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004264 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4265 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004266 }
4267 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4268}
4269
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004270// Implements part of 8.12.9 DefineOwnProperty.
4271// There are 3 cases that lead here:
4272// Step 4a - define a new data property.
4273// Steps 9b & 12 - replace an existing accessor property with a data property.
4274// Step 12 - update an existing data property with a data or generic
4275// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004276RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004277 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004278 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004279 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4280 CONVERT_ARG_CHECKED(String, name, 1);
4281 Handle<Object> obj_value = args.at<Object>(2);
4282
4283 CONVERT_CHECKED(Smi, flag, args[3]);
4284 int unchecked = flag->value();
4285 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4286
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004287 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4288
4289 // Check if this is an element.
4290 uint32_t index;
4291 bool is_element = name->AsArrayIndex(&index);
4292
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004293 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004294 // If elements are in fast case we always implicitly assume that:
4295 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004296 if (is_element && (attr != NONE ||
4297 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004298 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004299 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004300 // We do not need to do access checks here since these has already
4301 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004302 Handle<Object> proto(js_object->GetPrototype());
4303 // If proxy is detached, ignore the assignment. Alternatively,
4304 // we could throw an exception.
4305 if (proto->IsNull()) return *obj_value;
4306 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004307 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004308
4309 // Don't allow element properties to be redefined on objects with external
4310 // array elements.
4311 if (js_object->HasExternalArrayElements()) {
4312 Handle<Object> args[2] = { js_object, name };
4313 Handle<Object> error =
4314 isolate->factory()->NewTypeError("redef_external_array_element",
4315 HandleVector(args, 2));
4316 return isolate->Throw(*error);
4317 }
4318
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004319 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004320 // Make sure that we never go back to fast case.
4321 dictionary->set_requires_slow_elements();
4322 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004323 Handle<NumberDictionary> extended_dictionary =
4324 NumberDictionarySet(dictionary, index, obj_value, details);
4325 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004326 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004327 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4328 } else {
4329 js_object->set_elements(*extended_dictionary);
4330 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004331 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004332 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004333 }
4334
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004335 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004336 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004337
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004338 // To be compatible with safari we do not change the value on API objects
4339 // in defineProperty. Firefox disagrees here, and actually changes the value.
4340 if (result.IsProperty() &&
4341 (result.type() == CALLBACKS) &&
4342 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004343 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004344 }
4345
ager@chromium.org5c838252010-02-19 08:53:10 +00004346 // Take special care when attributes are different and there is already
4347 // a property. For simplicity we normalize the property which enables us
4348 // to not worry about changing the instance_descriptor and creating a new
4349 // map. The current version of SetObjectProperty does not handle attributes
4350 // correctly in the case where a property is a field and is reset with
4351 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004352 if (result.IsProperty() &&
4353 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004354 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004355 if (js_object->IsJSGlobalProxy()) {
4356 // Since the result is a property, the prototype will exist so
4357 // we don't have to check for null.
4358 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004359 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004360 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004361 // Use IgnoreAttributes version since a readonly property may be
4362 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004363 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4364 *obj_value,
4365 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004366 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004368 return Runtime::ForceSetObjectProperty(isolate,
4369 js_object,
4370 name,
4371 obj_value,
4372 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004373}
4374
4375
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004376// Special case for elements if any of the flags are true.
4377// If elements are in fast case we always implicitly assume that:
4378// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4379static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4380 Handle<JSObject> js_object,
4381 uint32_t index,
4382 Handle<Object> value,
4383 PropertyAttributes attr) {
4384 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004385 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004386 // Make sure that we never go back to fast case.
4387 dictionary->set_requires_slow_elements();
4388 PropertyDetails details = PropertyDetails(attr, NORMAL);
4389 Handle<NumberDictionary> extended_dictionary =
4390 NumberDictionarySet(dictionary, index, value, details);
4391 if (*extended_dictionary != *dictionary) {
4392 js_object->set_elements(*extended_dictionary);
4393 }
4394 return *value;
4395}
4396
4397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004398MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4399 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004400 Handle<Object> key,
4401 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004402 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004403 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004404 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004405
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004406 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004407 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004408 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004409 isolate->factory()->NewTypeError("non_object_property_store",
4410 HandleVector(args, 2));
4411 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004412 }
4413
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004414 if (object->IsJSProxy()) {
4415 bool has_pending_exception = false;
4416 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4417 if (has_pending_exception) return Failure::Exception();
4418 return JSProxy::cast(*object)->SetProperty(
4419 String::cast(*name), *value, attr, strict_mode);
4420 }
4421
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 // If the object isn't a JavaScript object, we ignore the store.
4423 if (!object->IsJSObject()) return *value;
4424
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004425 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4426
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004427 // Check if the given key is an array index.
4428 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004429 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004430 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4431 // of a string using [] notation. We need to support this too in
4432 // JavaScript.
4433 // In the case of a String object we just need to redirect the assignment to
4434 // the underlying string if the index is in range. Since the underlying
4435 // string does nothing with the assignment then we can ignore such
4436 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004437 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004439 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004440
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004441 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4442 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4443 }
4444
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004445 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004446 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447 return *value;
4448 }
4449
4450 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004451 Handle<Object> result;
4452 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004453 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4454 return NormalizeObjectSetElement(isolate,
4455 js_object,
4456 index,
4457 value,
4458 attr);
4459 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004460 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004461 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004462 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004463 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004464 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004465 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004466 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467 return *value;
4468 }
4469
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004470 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 bool has_pending_exception = false;
4472 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4473 if (has_pending_exception) return Failure::Exception();
4474 Handle<String> name = Handle<String>::cast(converted);
4475
4476 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004477 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004478 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004479 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004480 }
4481}
4482
4483
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004484MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4485 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004486 Handle<Object> key,
4487 Handle<Object> value,
4488 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004489 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004490
4491 // Check if the given key is an array index.
4492 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004493 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004494 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4495 // of a string using [] notation. We need to support this too in
4496 // JavaScript.
4497 // In the case of a String object we just need to redirect the assignment to
4498 // the underlying string if the index is in range. Since the underlying
4499 // string does nothing with the assignment then we can ignore such
4500 // assignments.
4501 if (js_object->IsStringObjectWithCharacterAt(index)) {
4502 return *value;
4503 }
4504
whesse@chromium.org7b260152011-06-20 15:33:18 +00004505 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004506 }
4507
4508 if (key->IsString()) {
4509 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004510 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004511 } else {
4512 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004513 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004514 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4515 *value,
4516 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004517 }
4518 }
4519
4520 // Call-back into JavaScript to convert the key to a string.
4521 bool has_pending_exception = false;
4522 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4523 if (has_pending_exception) return Failure::Exception();
4524 Handle<String> name = Handle<String>::cast(converted);
4525
4526 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004527 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004528 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004529 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004530 }
4531}
4532
4533
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004534MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004535 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004536 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004537 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004538
4539 // Check if the given key is an array index.
4540 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004541 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004542 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4543 // characters of a string using [] notation. In the case of a
4544 // String object we just need to redirect the deletion to the
4545 // underlying string if the index is in range. Since the
4546 // underlying string does nothing with the deletion, we can ignore
4547 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004548 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004549 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004550 }
4551
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004552 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004553 }
4554
4555 Handle<String> key_string;
4556 if (key->IsString()) {
4557 key_string = Handle<String>::cast(key);
4558 } else {
4559 // Call-back into JavaScript to convert the key to a string.
4560 bool has_pending_exception = false;
4561 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4562 if (has_pending_exception) return Failure::Exception();
4563 key_string = Handle<String>::cast(converted);
4564 }
4565
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004566 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004567 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004568}
4569
4570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004571RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004572 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004573 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004574
4575 Handle<Object> object = args.at<Object>(0);
4576 Handle<Object> key = args.at<Object>(1);
4577 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004578 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004579 RUNTIME_ASSERT(
4580 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004581 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004582 PropertyAttributes attributes =
4583 static_cast<PropertyAttributes>(unchecked_attributes);
4584
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004585 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004586 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004587 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4588 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004590
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004591 return Runtime::SetObjectProperty(isolate,
4592 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004593 key,
4594 value,
4595 attributes,
4596 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004597}
4598
4599
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004600RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4601 NoHandleAllocation ha;
4602 RUNTIME_ASSERT(args.length() == 1);
4603 Handle<Object> object = args.at<Object>(0);
4604 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4605}
4606
4607
4608RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4609 NoHandleAllocation ha;
4610 RUNTIME_ASSERT(args.length() == 1);
4611 Handle<Object> object = args.at<Object>(0);
4612 return TransitionElements(object, FAST_ELEMENTS, isolate);
4613}
4614
4615
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004616// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004617// This is used to decide if we should transform null and undefined
4618// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004619RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004620 NoHandleAllocation ha;
4621 RUNTIME_ASSERT(args.length() == 1);
4622
4623 Handle<Object> object = args.at<Object>(0);
4624
4625 if (object->IsJSFunction()) {
4626 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004627 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004628 }
4629 return isolate->heap()->undefined_value();
4630}
4631
4632
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004633RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4634 RUNTIME_ASSERT(args.length() == 5);
4635 CONVERT_ARG_CHECKED(JSObject, object, 0);
4636 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4637 Handle<Object> value = args.at<Object>(2);
4638 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4639 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4640 HandleScope scope;
4641
4642 Object* raw_boilerplate_object = literals->get(literal_index);
4643 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4644#if DEBUG
4645 ElementsKind elements_kind = object->GetElementsKind();
4646#endif
4647 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4648 // Smis should never trigger transitions.
4649 ASSERT(!value->IsSmi());
4650
4651 if (value->IsNumber()) {
4652 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
4653 TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4654 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4655 FixedDoubleArray* double_array =
4656 FixedDoubleArray::cast(object->elements());
4657 HeapNumber* number = HeapNumber::cast(*value);
4658 double_array->set(store_index, number->Number());
4659 } else {
4660 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4661 elements_kind == FAST_DOUBLE_ELEMENTS);
4662 TransitionElementsKind(object, FAST_ELEMENTS);
4663 FixedArray* object_array =
4664 FixedArray::cast(object->elements());
4665 object_array->set(store_index, *value);
4666 }
4667 return *object;
4668}
4669
4670
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004671// Set a local property, even if it is READ_ONLY. If the property does not
4672// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004673RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004674 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004675 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004676 CONVERT_CHECKED(JSObject, object, args[0]);
4677 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004678 // Compute attributes.
4679 PropertyAttributes attributes = NONE;
4680 if (args.length() == 4) {
4681 CONVERT_CHECKED(Smi, value_obj, args[3]);
4682 int unchecked_value = value_obj->value();
4683 // Only attribute bits should be set.
4684 RUNTIME_ASSERT(
4685 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4686 attributes = static_cast<PropertyAttributes>(unchecked_value);
4687 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004689 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004690 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004691}
4692
4693
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004694RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004696 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004697
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004698 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004699 CONVERT_CHECKED(String, key, args[1]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004700 CONVERT_STRICT_MODE_ARG(strict_mode, 2);
4701 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004702 ? JSReceiver::STRICT_DELETION
4703 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004704}
4705
4706
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004707static Object* HasLocalPropertyImplementation(Isolate* isolate,
4708 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004709 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004710 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004711 // Handle hidden prototypes. If there's a hidden prototype above this thing
4712 // then we have to check it for properties, because they are supposed to
4713 // look like they are on this object.
4714 Handle<Object> proto(object->GetPrototype());
4715 if (proto->IsJSObject() &&
4716 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004717 return HasLocalPropertyImplementation(isolate,
4718 Handle<JSObject>::cast(proto),
4719 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004720 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004721 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004722}
4723
4724
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004725RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004726 NoHandleAllocation ha;
4727 ASSERT(args.length() == 2);
4728 CONVERT_CHECKED(String, key, args[1]);
4729
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004730 uint32_t index;
4731 const bool key_is_array_index = key->AsArrayIndex(&index);
4732
ager@chromium.org9085a012009-05-11 19:22:57 +00004733 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004734 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004735 if (obj->IsJSObject()) {
4736 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004737 // Fast case: either the key is a real named property or it is not
4738 // an array index and there are no interceptors or hidden
4739 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004740 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004741 Map* map = object->map();
4742 if (!key_is_array_index &&
4743 !map->has_named_interceptor() &&
4744 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4745 return isolate->heap()->false_value();
4746 }
4747 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004748 HandleScope scope(isolate);
4749 return HasLocalPropertyImplementation(isolate,
4750 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004751 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004752 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004753 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004754 String* string = String::cast(obj);
4755 if (index < static_cast<uint32_t>(string->length())) {
4756 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757 }
4758 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004759 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760}
4761
4762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004763RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 NoHandleAllocation na;
4765 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004766 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4767 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004768
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004769 bool result = receiver->HasProperty(key);
4770 if (isolate->has_pending_exception()) return Failure::Exception();
4771 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004772}
4773
4774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004775RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004776 NoHandleAllocation na;
4777 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004778 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4779 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004780
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004781 bool result = receiver->HasElement(index->value());
4782 if (isolate->has_pending_exception()) return Failure::Exception();
4783 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784}
4785
4786
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004787RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004788 NoHandleAllocation ha;
4789 ASSERT(args.length() == 2);
4790
4791 CONVERT_CHECKED(JSObject, object, args[0]);
4792 CONVERT_CHECKED(String, key, args[1]);
4793
4794 uint32_t index;
4795 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004796 JSObject::LocalElementType type = object->HasLocalElement(index);
4797 switch (type) {
4798 case JSObject::UNDEFINED_ELEMENT:
4799 case JSObject::STRING_CHARACTER_ELEMENT:
4800 return isolate->heap()->false_value();
4801 case JSObject::INTERCEPTED_ELEMENT:
4802 case JSObject::FAST_ELEMENT:
4803 return isolate->heap()->true_value();
4804 case JSObject::DICTIONARY_ELEMENT: {
4805 if (object->IsJSGlobalProxy()) {
4806 Object* proto = object->GetPrototype();
4807 if (proto->IsNull()) {
4808 return isolate->heap()->false_value();
4809 }
4810 ASSERT(proto->IsJSGlobalObject());
4811 object = JSObject::cast(proto);
4812 }
4813 FixedArray* elements = FixedArray::cast(object->elements());
4814 NumberDictionary* dictionary = NULL;
4815 if (elements->map() ==
4816 isolate->heap()->non_strict_arguments_elements_map()) {
4817 dictionary = NumberDictionary::cast(elements->get(1));
4818 } else {
4819 dictionary = NumberDictionary::cast(elements);
4820 }
4821 int entry = dictionary->FindEntry(index);
4822 ASSERT(entry != NumberDictionary::kNotFound);
4823 PropertyDetails details = dictionary->DetailsAt(entry);
4824 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4825 }
4826 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827 }
4828
ager@chromium.org870a0b62008-11-04 11:43:05 +00004829 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004830 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831}
4832
4833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004834RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004835 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004837 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4838 bool threw = false;
4839 Handle<JSArray> result = GetKeysFor(object, &threw);
4840 if (threw) return Failure::Exception();
4841 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004842}
4843
4844
4845// Returns either a FixedArray as Runtime_GetPropertyNames,
4846// or, if the given object has an enum cache that contains
4847// all enumerable properties of the object and its prototypes
4848// have none, the map of the object. This is used to speed up
4849// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004850RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004851 ASSERT(args.length() == 1);
4852
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004853 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004854
4855 if (raw_object->IsSimpleEnum()) return raw_object->map();
4856
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004857 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004858 Handle<JSReceiver> object(raw_object);
4859 bool threw = false;
4860 Handle<FixedArray> content =
4861 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4862 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004863
4864 // Test again, since cache may have been built by preceding call.
4865 if (object->IsSimpleEnum()) return object->map();
4866
4867 return *content;
4868}
4869
4870
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004871// Find the length of the prototype chain that is to to handled as one. If a
4872// prototype object is hidden it is to be viewed as part of the the object it
4873// is prototype for.
4874static int LocalPrototypeChainLength(JSObject* obj) {
4875 int count = 1;
4876 Object* proto = obj->GetPrototype();
4877 while (proto->IsJSObject() &&
4878 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4879 count++;
4880 proto = JSObject::cast(proto)->GetPrototype();
4881 }
4882 return count;
4883}
4884
4885
4886// Return the names of the local named properties.
4887// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004888RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004889 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004890 ASSERT(args.length() == 1);
4891 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004892 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004893 }
4894 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4895
4896 // Skip the global proxy as it has no properties and always delegates to the
4897 // real global object.
4898 if (obj->IsJSGlobalProxy()) {
4899 // Only collect names if access is permitted.
4900 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004901 !isolate->MayNamedAccess(*obj,
4902 isolate->heap()->undefined_value(),
4903 v8::ACCESS_KEYS)) {
4904 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4905 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004906 }
4907 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4908 }
4909
4910 // Find the number of objects making up this.
4911 int length = LocalPrototypeChainLength(*obj);
4912
4913 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004914 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004915 int total_property_count = 0;
4916 Handle<JSObject> jsproto = obj;
4917 for (int i = 0; i < length; i++) {
4918 // Only collect names if access is permitted.
4919 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004920 !isolate->MayNamedAccess(*jsproto,
4921 isolate->heap()->undefined_value(),
4922 v8::ACCESS_KEYS)) {
4923 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4924 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004925 }
4926 int n;
4927 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4928 local_property_count[i] = n;
4929 total_property_count += n;
4930 if (i < length - 1) {
4931 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4932 }
4933 }
4934
4935 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004936 Handle<FixedArray> names =
4937 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004938
4939 // Get the property names.
4940 jsproto = obj;
4941 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004942 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004943 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004944 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4945 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004946 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004947 proto_with_hidden_properties++;
4948 }
4949 if (i < length - 1) {
4950 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4951 }
4952 }
4953
4954 // Filter out name of hidden propeties object.
4955 if (proto_with_hidden_properties > 0) {
4956 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004957 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004958 names->length() - proto_with_hidden_properties);
4959 int dest_pos = 0;
4960 for (int i = 0; i < total_property_count; i++) {
4961 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004962 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004963 continue;
4964 }
4965 names->set(dest_pos++, name);
4966 }
4967 }
4968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004969 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004970}
4971
4972
4973// Return the names of the local indexed properties.
4974// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004975RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004976 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004977 ASSERT(args.length() == 1);
4978 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004979 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004980 }
4981 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4982
4983 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004984 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004985 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004986 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004987}
4988
4989
4990// Return information on whether an object has a named or indexed interceptor.
4991// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004992RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004993 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004994 ASSERT(args.length() == 1);
4995 if (!args[0]->IsJSObject()) {
4996 return Smi::FromInt(0);
4997 }
4998 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4999
5000 int result = 0;
5001 if (obj->HasNamedInterceptor()) result |= 2;
5002 if (obj->HasIndexedInterceptor()) result |= 1;
5003
5004 return Smi::FromInt(result);
5005}
5006
5007
5008// Return property names from named interceptor.
5009// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005010RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005011 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005012 ASSERT(args.length() == 1);
5013 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5014
5015 if (obj->HasNamedInterceptor()) {
5016 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5017 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5018 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005019 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005020}
5021
5022
5023// Return element names from indexed interceptor.
5024// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005025RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005026 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005027 ASSERT(args.length() == 1);
5028 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5029
5030 if (obj->HasIndexedInterceptor()) {
5031 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5032 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5033 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005034 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005035}
5036
5037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005038RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005039 ASSERT_EQ(args.length(), 1);
5040 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005041 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005042 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005043
5044 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005045 // Do access checks before going to the global object.
5046 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005047 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005048 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005049 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5050 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005051 }
5052
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005053 Handle<Object> proto(object->GetPrototype());
5054 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005055 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005056 object = Handle<JSObject>::cast(proto);
5057 }
5058
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005059 bool threw = false;
5060 Handle<FixedArray> contents =
5061 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5062 if (threw) return Failure::Exception();
5063
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005064 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5065 // property array and since the result is mutable we have to create
5066 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005067 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005069 for (int i = 0; i < length; i++) {
5070 Object* entry = contents->get(i);
5071 if (entry->IsString()) {
5072 copy->set(i, entry);
5073 } else {
5074 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005075 HandleScope scope(isolate);
5076 Handle<Object> entry_handle(entry, isolate);
5077 Handle<Object> entry_str =
5078 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005079 copy->set(i, *entry_str);
5080 }
5081 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005082 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005083}
5084
5085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005086RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005087 NoHandleAllocation ha;
5088 ASSERT(args.length() == 1);
5089
5090 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005091 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005092 it.AdvanceToArgumentsFrame();
5093 JavaScriptFrame* frame = it.frame();
5094
5095 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005096 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005097
5098 // Try to convert the key to an index. If successful and within
5099 // index return the the argument from the frame.
5100 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005101 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005102 return frame->GetParameter(index);
5103 }
5104
5105 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005106 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005107 bool exception = false;
5108 Handle<Object> converted =
5109 Execution::ToString(args.at<Object>(0), &exception);
5110 if (exception) return Failure::Exception();
5111 Handle<String> key = Handle<String>::cast(converted);
5112
5113 // Try to convert the string key into an array index.
5114 if (key->AsArrayIndex(&index)) {
5115 if (index < n) {
5116 return frame->GetParameter(index);
5117 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005118 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005119 }
5120 }
5121
5122 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005123 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5124 if (key->Equals(isolate->heap()->callee_symbol())) {
5125 Object* function = frame->function();
5126 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005127 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005128 return isolate->Throw(*isolate->factory()->NewTypeError(
5129 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5130 }
5131 return function;
5132 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005133
5134 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005135 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005136}
5137
5138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005139RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005140 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005141
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005142 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005143 Handle<Object> object = args.at<Object>(0);
5144 if (object->IsJSObject()) {
5145 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005146 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005147 MaybeObject* ok = js_object->TransformToFastProperties(0);
5148 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005149 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005150 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005151 return *object;
5152}
5153
5154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005155RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005156 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005157
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005158 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005159 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005160 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005161 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005162 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005163 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005164 return *object;
5165}
5166
5167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005168RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005169 NoHandleAllocation ha;
5170 ASSERT(args.length() == 1);
5171
5172 return args[0]->ToBoolean();
5173}
5174
5175
5176// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5177// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005178RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005179 NoHandleAllocation ha;
5180
5181 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005182 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005183 HeapObject* heap_obj = HeapObject::cast(obj);
5184
5185 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005186 if (heap_obj->map()->is_undetectable()) {
5187 return isolate->heap()->undefined_symbol();
5188 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005189
5190 InstanceType instance_type = heap_obj->map()->instance_type();
5191 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005192 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005193 }
5194
5195 switch (instance_type) {
5196 case ODDBALL_TYPE:
5197 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005198 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005199 }
5200 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005201 return FLAG_harmony_typeof
5202 ? isolate->heap()->null_symbol()
5203 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005204 }
5205 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005206 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005207 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005208 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005209 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005210 default:
5211 // For any kind of object not handled above, the spec rule for
5212 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005213 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005214 }
5215}
5216
5217
lrn@chromium.org25156de2010-04-06 13:10:27 +00005218static bool AreDigits(const char*s, int from, int to) {
5219 for (int i = from; i < to; i++) {
5220 if (s[i] < '0' || s[i] > '9') return false;
5221 }
5222
5223 return true;
5224}
5225
5226
5227static int ParseDecimalInteger(const char*s, int from, int to) {
5228 ASSERT(to - from < 10); // Overflow is not possible.
5229 ASSERT(from < to);
5230 int d = s[from] - '0';
5231
5232 for (int i = from + 1; i < to; i++) {
5233 d = 10 * d + (s[i] - '0');
5234 }
5235
5236 return d;
5237}
5238
5239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005240RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005241 NoHandleAllocation ha;
5242 ASSERT(args.length() == 1);
5243 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005244 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005245
5246 // Fast case: short integer or some sorts of junk values.
5247 int len = subject->length();
5248 if (subject->IsSeqAsciiString()) {
5249 if (len == 0) return Smi::FromInt(0);
5250
5251 char const* data = SeqAsciiString::cast(subject)->GetChars();
5252 bool minus = (data[0] == '-');
5253 int start_pos = (minus ? 1 : 0);
5254
5255 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005256 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005257 } else if (data[start_pos] > '9') {
5258 // Fast check for a junk value. A valid string may start from a
5259 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5260 // the 'I' character ('Infinity'). All of that have codes not greater than
5261 // '9' except 'I'.
5262 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005263 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005264 }
5265 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5266 // The maximal/minimal smi has 10 digits. If the string has less digits we
5267 // know it will fit into the smi-data type.
5268 int d = ParseDecimalInteger(data, start_pos, len);
5269 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005270 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005271 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005272 } else if (!subject->HasHashCode() &&
5273 len <= String::kMaxArrayIndexSize &&
5274 (len == 1 || data[0] != '0')) {
5275 // String hash is not calculated yet but all the data are present.
5276 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005277 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005278#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005279 subject->Hash(); // Force hash calculation.
5280 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5281 static_cast<int>(hash));
5282#endif
5283 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005284 }
5285 return Smi::FromInt(d);
5286 }
5287 }
5288
5289 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005290 return isolate->heap()->NumberFromDouble(
5291 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005292}
5293
5294
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005295RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005296 NoHandleAllocation ha;
5297 ASSERT(args.length() == 1);
5298
5299 CONVERT_CHECKED(JSArray, codes, args[0]);
5300 int length = Smi::cast(codes->length())->value();
5301
5302 // Check if the string can be ASCII.
5303 int i;
5304 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005305 Object* element;
5306 { MaybeObject* maybe_element = codes->GetElement(i);
5307 // We probably can't get an exception here, but just in order to enforce
5308 // the checking of inputs in the runtime calls we check here.
5309 if (!maybe_element->ToObject(&element)) return maybe_element;
5310 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005311 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5312 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5313 break;
5314 }
5315
lrn@chromium.org303ada72010-10-27 09:33:13 +00005316 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005317 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005318 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005320 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005321 }
5322
lrn@chromium.org303ada72010-10-27 09:33:13 +00005323 Object* object = NULL;
5324 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005325 String* result = String::cast(object);
5326 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005327 Object* element;
5328 { MaybeObject* maybe_element = codes->GetElement(i);
5329 if (!maybe_element->ToObject(&element)) return maybe_element;
5330 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005331 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005332 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005333 }
5334 return result;
5335}
5336
5337
5338// kNotEscaped is generated by the following:
5339//
5340// #!/bin/perl
5341// for (my $i = 0; $i < 256; $i++) {
5342// print "\n" if $i % 16 == 0;
5343// my $c = chr($i);
5344// my $escaped = 1;
5345// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5346// print $escaped ? "0, " : "1, ";
5347// }
5348
5349
5350static bool IsNotEscaped(uint16_t character) {
5351 // Only for 8 bit characters, the rest are always escaped (in a different way)
5352 ASSERT(character < 256);
5353 static const char kNotEscaped[256] = {
5354 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5355 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5357 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5358 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5359 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5360 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5361 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5364 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5370 };
5371 return kNotEscaped[character] != 0;
5372}
5373
5374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005375RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005376 const char hex_chars[] = "0123456789ABCDEF";
5377 NoHandleAllocation ha;
5378 ASSERT(args.length() == 1);
5379 CONVERT_CHECKED(String, source, args[0]);
5380
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005381 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005382
5383 int escaped_length = 0;
5384 int length = source->length();
5385 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005386 Access<StringInputBuffer> buffer(
5387 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005388 buffer->Reset(source);
5389 while (buffer->has_more()) {
5390 uint16_t character = buffer->GetNext();
5391 if (character >= 256) {
5392 escaped_length += 6;
5393 } else if (IsNotEscaped(character)) {
5394 escaped_length++;
5395 } else {
5396 escaped_length += 3;
5397 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005398 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005399 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005400 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005401 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005402 return Failure::OutOfMemoryException();
5403 }
5404 }
5405 }
5406 // No length change implies no change. Return original string if no change.
5407 if (escaped_length == length) {
5408 return source;
5409 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005410 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005411 { MaybeObject* maybe_o =
5412 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005413 if (!maybe_o->ToObject(&o)) return maybe_o;
5414 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005415 String* destination = String::cast(o);
5416 int dest_position = 0;
5417
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005418 Access<StringInputBuffer> buffer(
5419 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005420 buffer->Rewind();
5421 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005422 uint16_t chr = buffer->GetNext();
5423 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005424 destination->Set(dest_position, '%');
5425 destination->Set(dest_position+1, 'u');
5426 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5427 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5428 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5429 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005430 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005431 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005432 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005433 dest_position++;
5434 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005435 destination->Set(dest_position, '%');
5436 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5437 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005438 dest_position += 3;
5439 }
5440 }
5441 return destination;
5442}
5443
5444
5445static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5446 static const signed char kHexValue['g'] = {
5447 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5448 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5449 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5450 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5451 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5452 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5453 -1, 10, 11, 12, 13, 14, 15 };
5454
5455 if (character1 > 'f') return -1;
5456 int hi = kHexValue[character1];
5457 if (hi == -1) return -1;
5458 if (character2 > 'f') return -1;
5459 int lo = kHexValue[character2];
5460 if (lo == -1) return -1;
5461 return (hi << 4) + lo;
5462}
5463
5464
ager@chromium.org870a0b62008-11-04 11:43:05 +00005465static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005466 int i,
5467 int length,
5468 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005469 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005470 int32_t hi = 0;
5471 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005472 if (character == '%' &&
5473 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005474 source->Get(i + 1) == 'u' &&
5475 (hi = TwoDigitHex(source->Get(i + 2),
5476 source->Get(i + 3))) != -1 &&
5477 (lo = TwoDigitHex(source->Get(i + 4),
5478 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 *step = 6;
5480 return (hi << 8) + lo;
5481 } else if (character == '%' &&
5482 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005483 (lo = TwoDigitHex(source->Get(i + 1),
5484 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005485 *step = 3;
5486 return lo;
5487 } else {
5488 *step = 1;
5489 return character;
5490 }
5491}
5492
5493
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005494RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005495 NoHandleAllocation ha;
5496 ASSERT(args.length() == 1);
5497 CONVERT_CHECKED(String, source, args[0]);
5498
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005499 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005500
5501 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005502 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005503
5504 int unescaped_length = 0;
5505 for (int i = 0; i < length; unescaped_length++) {
5506 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005507 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005508 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005509 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005510 i += step;
5511 }
5512
5513 // No length change implies no change. Return original string if no change.
5514 if (unescaped_length == length)
5515 return source;
5516
lrn@chromium.org303ada72010-10-27 09:33:13 +00005517 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005518 { MaybeObject* maybe_o =
5519 ascii ?
5520 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5521 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005522 if (!maybe_o->ToObject(&o)) return maybe_o;
5523 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005524 String* destination = String::cast(o);
5525
5526 int dest_position = 0;
5527 for (int i = 0; i < length; dest_position++) {
5528 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005529 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005530 i += step;
5531 }
5532 return destination;
5533}
5534
5535
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005536static const unsigned int kQuoteTableLength = 128u;
5537
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005538static const int kJsonQuotesCharactersPerEntry = 8;
5539static const char* const JsonQuotes =
5540 "\\u0000 \\u0001 \\u0002 \\u0003 "
5541 "\\u0004 \\u0005 \\u0006 \\u0007 "
5542 "\\b \\t \\n \\u000b "
5543 "\\f \\r \\u000e \\u000f "
5544 "\\u0010 \\u0011 \\u0012 \\u0013 "
5545 "\\u0014 \\u0015 \\u0016 \\u0017 "
5546 "\\u0018 \\u0019 \\u001a \\u001b "
5547 "\\u001c \\u001d \\u001e \\u001f "
5548 " ! \\\" # "
5549 "$ % & ' "
5550 "( ) * + "
5551 ", - . / "
5552 "0 1 2 3 "
5553 "4 5 6 7 "
5554 "8 9 : ; "
5555 "< = > ? "
5556 "@ A B C "
5557 "D E F G "
5558 "H I J K "
5559 "L M N O "
5560 "P Q R S "
5561 "T U V W "
5562 "X Y Z [ "
5563 "\\\\ ] ^ _ "
5564 "` a b c "
5565 "d e f g "
5566 "h i j k "
5567 "l m n o "
5568 "p q r s "
5569 "t u v w "
5570 "x y z { "
5571 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005572
5573
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005574// For a string that is less than 32k characters it should always be
5575// possible to allocate it in new space.
5576static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5577
5578
5579// Doing JSON quoting cannot make the string more than this many times larger.
5580static const int kJsonQuoteWorstCaseBlowup = 6;
5581
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005582static const int kSpaceForQuotesAndComma = 3;
5583static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005584
5585// Covers the entire ASCII range (all other characters are unchanged by JSON
5586// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005587static const byte JsonQuoteLengths[kQuoteTableLength] = {
5588 6, 6, 6, 6, 6, 6, 6, 6,
5589 2, 2, 2, 6, 2, 2, 6, 6,
5590 6, 6, 6, 6, 6, 6, 6, 6,
5591 6, 6, 6, 6, 6, 6, 6, 6,
5592 1, 1, 2, 1, 1, 1, 1, 1,
5593 1, 1, 1, 1, 1, 1, 1, 1,
5594 1, 1, 1, 1, 1, 1, 1, 1,
5595 1, 1, 1, 1, 1, 1, 1, 1,
5596 1, 1, 1, 1, 1, 1, 1, 1,
5597 1, 1, 1, 1, 1, 1, 1, 1,
5598 1, 1, 1, 1, 1, 1, 1, 1,
5599 1, 1, 1, 1, 2, 1, 1, 1,
5600 1, 1, 1, 1, 1, 1, 1, 1,
5601 1, 1, 1, 1, 1, 1, 1, 1,
5602 1, 1, 1, 1, 1, 1, 1, 1,
5603 1, 1, 1, 1, 1, 1, 1, 1,
5604};
5605
5606
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005607template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005608MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005609
5610
5611template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005612MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5613 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005614}
5615
5616
5617template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005618MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5619 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005620}
5621
5622
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005623template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005624static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5625 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005626 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005627 const Char* read_cursor = characters.start();
5628 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005629 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005630 int quoted_length = kSpaceForQuotes;
5631 while (read_cursor < end) {
5632 Char c = *(read_cursor++);
5633 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5634 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005635 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005636 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005637 }
5638 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005639 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5640 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005641 Object* new_object;
5642 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005643 return new_alloc;
5644 }
5645 StringType* new_string = StringType::cast(new_object);
5646
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005647 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005648 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005649 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005650 *(write_cursor++) = '"';
5651
5652 read_cursor = characters.start();
5653 while (read_cursor < end) {
5654 Char c = *(read_cursor++);
5655 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5656 *(write_cursor++) = c;
5657 } else {
5658 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5659 const char* replacement = JsonQuotes +
5660 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5661 for (int i = 0; i < len; i++) {
5662 *write_cursor++ = *replacement++;
5663 }
5664 }
5665 }
5666 *(write_cursor++) = '"';
5667 return new_string;
5668}
5669
5670
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005671template <typename SinkChar, typename SourceChar>
5672static inline SinkChar* WriteQuoteJsonString(
5673 Isolate* isolate,
5674 SinkChar* write_cursor,
5675 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005676 // SinkChar is only char if SourceChar is guaranteed to be char.
5677 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005678 const SourceChar* read_cursor = characters.start();
5679 const SourceChar* end = read_cursor + characters.length();
5680 *(write_cursor++) = '"';
5681 while (read_cursor < end) {
5682 SourceChar c = *(read_cursor++);
5683 if (sizeof(SourceChar) > 1u &&
5684 static_cast<unsigned>(c) >= kQuoteTableLength) {
5685 *(write_cursor++) = static_cast<SinkChar>(c);
5686 } else {
5687 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5688 const char* replacement = JsonQuotes +
5689 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5690 write_cursor[0] = replacement[0];
5691 if (len > 1) {
5692 write_cursor[1] = replacement[1];
5693 if (len > 2) {
5694 ASSERT(len == 6);
5695 write_cursor[2] = replacement[2];
5696 write_cursor[3] = replacement[3];
5697 write_cursor[4] = replacement[4];
5698 write_cursor[5] = replacement[5];
5699 }
5700 }
5701 write_cursor += len;
5702 }
5703 }
5704 *(write_cursor++) = '"';
5705 return write_cursor;
5706}
5707
5708
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005709template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005710static MaybeObject* QuoteJsonString(Isolate* isolate,
5711 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005712 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005713 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005714 int worst_case_length =
5715 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005716 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005717 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005718 }
5719
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005720 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5721 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005722 Object* new_object;
5723 if (!new_alloc->ToObject(&new_object)) {
5724 return new_alloc;
5725 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005726 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005727 // Even if our string is small enough to fit in new space we still have to
5728 // handle it being allocated in old space as may happen in the third
5729 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5730 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005731 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005732 }
5733 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005734 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005735
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005736 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005737 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005738 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005739 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5740 write_cursor,
5741 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005742 int final_length = static_cast<int>(
5743 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005744 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005745 isolate->heap()->new_space()->
5746 template ShrinkStringAtAllocationBoundary<StringType>(
5747 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005748 return new_string;
5749}
5750
5751
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005752RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005753 NoHandleAllocation ha;
5754 CONVERT_CHECKED(String, str, args[0]);
5755 if (!str->IsFlat()) {
5756 MaybeObject* try_flatten = str->TryFlatten();
5757 Object* flat;
5758 if (!try_flatten->ToObject(&flat)) {
5759 return try_flatten;
5760 }
5761 str = String::cast(flat);
5762 ASSERT(str->IsFlat());
5763 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005764 String::FlatContent flat = str->GetFlatContent();
5765 ASSERT(flat.IsFlat());
5766 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005767 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005768 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005769 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005770 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005771 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005772 }
5773}
5774
5775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005776RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005777 NoHandleAllocation ha;
5778 CONVERT_CHECKED(String, str, args[0]);
5779 if (!str->IsFlat()) {
5780 MaybeObject* try_flatten = str->TryFlatten();
5781 Object* flat;
5782 if (!try_flatten->ToObject(&flat)) {
5783 return try_flatten;
5784 }
5785 str = String::cast(flat);
5786 ASSERT(str->IsFlat());
5787 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005788 String::FlatContent flat = str->GetFlatContent();
5789 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005790 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005791 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005792 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005794 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005795 }
5796}
5797
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005798
5799template <typename Char, typename StringType>
5800static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5801 FixedArray* array,
5802 int worst_case_length) {
5803 int length = array->length();
5804
5805 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5806 worst_case_length);
5807 Object* new_object;
5808 if (!new_alloc->ToObject(&new_object)) {
5809 return new_alloc;
5810 }
5811 if (!isolate->heap()->new_space()->Contains(new_object)) {
5812 // Even if our string is small enough to fit in new space we still have to
5813 // handle it being allocated in old space as may happen in the third
5814 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5815 // CEntryStub::GenerateCore.
5816 return isolate->heap()->undefined_value();
5817 }
5818 AssertNoAllocation no_gc;
5819 StringType* new_string = StringType::cast(new_object);
5820 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5821
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005822 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005823 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005824 *(write_cursor++) = '[';
5825 for (int i = 0; i < length; i++) {
5826 if (i != 0) *(write_cursor++) = ',';
5827 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005828 String::FlatContent content = str->GetFlatContent();
5829 ASSERT(content.IsFlat());
5830 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005831 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5832 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005833 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005834 } else {
5835 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5836 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005837 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005838 }
5839 }
5840 *(write_cursor++) = ']';
5841
5842 int final_length = static_cast<int>(
5843 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005844 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005845 isolate->heap()->new_space()->
5846 template ShrinkStringAtAllocationBoundary<StringType>(
5847 new_string, final_length);
5848 return new_string;
5849}
5850
5851
5852RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5853 NoHandleAllocation ha;
5854 ASSERT(args.length() == 1);
5855 CONVERT_CHECKED(JSArray, array, args[0]);
5856
5857 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5858 FixedArray* elements = FixedArray::cast(array->elements());
5859 int n = elements->length();
5860 bool ascii = true;
5861 int total_length = 0;
5862
5863 for (int i = 0; i < n; i++) {
5864 Object* elt = elements->get(i);
5865 if (!elt->IsString()) return isolate->heap()->undefined_value();
5866 String* element = String::cast(elt);
5867 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5868 total_length += element->length();
5869 if (ascii && element->IsTwoByteRepresentation()) {
5870 ascii = false;
5871 }
5872 }
5873
5874 int worst_case_length =
5875 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5876 + total_length * kJsonQuoteWorstCaseBlowup;
5877
5878 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5879 return isolate->heap()->undefined_value();
5880 }
5881
5882 if (ascii) {
5883 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5884 elements,
5885 worst_case_length);
5886 } else {
5887 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5888 elements,
5889 worst_case_length);
5890 }
5891}
5892
5893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005894RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005895 NoHandleAllocation ha;
5896
5897 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005898 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005899
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005900 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005901
lrn@chromium.org25156de2010-04-06 13:10:27 +00005902 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005903 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005904 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005905}
5906
5907
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005908RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005909 NoHandleAllocation ha;
5910 CONVERT_CHECKED(String, str, args[0]);
5911
5912 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005913 double value = StringToDouble(isolate->unicode_cache(),
5914 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005915
5916 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005917 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918}
5919
5920
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005922MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005923 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005924 String* s,
5925 int length,
5926 int input_string_length,
5927 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005928 // We try this twice, once with the assumption that the result is no longer
5929 // than the input and, if that assumption breaks, again with the exact
5930 // length. This may not be pretty, but it is nicer than what was here before
5931 // and I hereby claim my vaffel-is.
5932 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005933 // Allocate the resulting string.
5934 //
5935 // NOTE: This assumes that the upper/lower case of an ascii
5936 // character is also ascii. This is currently the case, but it
5937 // might break in the future if we implement more context and locale
5938 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005939 Object* o;
5940 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005941 ? isolate->heap()->AllocateRawAsciiString(length)
5942 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005943 if (!maybe_o->ToObject(&o)) return maybe_o;
5944 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005945 String* result = String::cast(o);
5946 bool has_changed_character = false;
5947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005948 // Convert all characters to upper case, assuming that they will fit
5949 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005950 Access<StringInputBuffer> buffer(
5951 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005952 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005953 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954 // We can assume that the string is not empty
5955 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005956 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005957 bool has_next = buffer->has_more();
5958 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005959 int char_length = mapping->get(current, next, chars);
5960 if (char_length == 0) {
5961 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005962 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005963 i++;
5964 } else if (char_length == 1) {
5965 // Common case: converting the letter resulted in one character.
5966 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005967 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005968 has_changed_character = true;
5969 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005970 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 // We've assumed that the result would be as long as the
5972 // input but here is a character that converts to several
5973 // characters. No matter, we calculate the exact length
5974 // of the result and try the whole thing again.
5975 //
5976 // Note that this leaves room for optimization. We could just
5977 // memcpy what we already have to the result string. Also,
5978 // the result string is the last object allocated we could
5979 // "realloc" it and probably, in the vast majority of cases,
5980 // extend the existing string to be able to hold the full
5981 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005982 int next_length = 0;
5983 if (has_next) {
5984 next_length = mapping->get(next, 0, chars);
5985 if (next_length == 0) next_length = 1;
5986 }
5987 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988 while (buffer->has_more()) {
5989 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005990 // NOTE: we use 0 as the next character here because, while
5991 // the next character may affect what a character converts to,
5992 // it does not in any case affect the length of what it convert
5993 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994 int char_length = mapping->get(current, 0, chars);
5995 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005996 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005997 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005998 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005999 return Failure::OutOfMemoryException();
6000 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006002 // Try again with the real length.
6003 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006004 } else {
6005 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006006 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 i++;
6008 }
6009 has_changed_character = true;
6010 }
6011 current = next;
6012 }
6013 if (has_changed_character) {
6014 return result;
6015 } else {
6016 // If we didn't actually change anything in doing the conversion
6017 // we simple return the result and let the converted string
6018 // become garbage; there is no reason to keep two identical strings
6019 // alive.
6020 return s;
6021 }
6022}
6023
6024
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006025namespace {
6026
lrn@chromium.org303ada72010-10-27 09:33:13 +00006027static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6028
6029
6030// Given a word and two range boundaries returns a word with high bit
6031// set in every byte iff the corresponding input byte was strictly in
6032// the range (m, n). All the other bits in the result are cleared.
6033// This function is only useful when it can be inlined and the
6034// boundaries are statically known.
6035// Requires: all bytes in the input word and the boundaries must be
6036// ascii (less than 0x7F).
6037static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6038 // Every byte in an ascii string is less than or equal to 0x7F.
6039 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6040 // Use strict inequalities since in edge cases the function could be
6041 // further simplified.
6042 ASSERT(0 < m && m < n && n < 0x7F);
6043 // Has high bit set in every w byte less than n.
6044 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6045 // Has high bit set in every w byte greater than m.
6046 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6047 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6048}
6049
6050
6051enum AsciiCaseConversion {
6052 ASCII_TO_LOWER,
6053 ASCII_TO_UPPER
6054};
6055
6056
6057template <AsciiCaseConversion dir>
6058struct FastAsciiConverter {
6059 static bool Convert(char* dst, char* src, int length) {
6060#ifdef DEBUG
6061 char* saved_dst = dst;
6062 char* saved_src = src;
6063#endif
6064 // We rely on the distance between upper and lower case letters
6065 // being a known power of 2.
6066 ASSERT('a' - 'A' == (1 << 5));
6067 // Boundaries for the range of input characters than require conversion.
6068 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6069 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6070 bool changed = false;
6071 char* const limit = src + length;
6072#ifdef V8_HOST_CAN_READ_UNALIGNED
6073 // Process the prefix of the input that requires no conversion one
6074 // (machine) word at a time.
6075 while (src <= limit - sizeof(uintptr_t)) {
6076 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6077 if (AsciiRangeMask(w, lo, hi) != 0) {
6078 changed = true;
6079 break;
6080 }
6081 *reinterpret_cast<uintptr_t*>(dst) = w;
6082 src += sizeof(uintptr_t);
6083 dst += sizeof(uintptr_t);
6084 }
6085 // Process the remainder of the input performing conversion when
6086 // required one word at a time.
6087 while (src <= limit - sizeof(uintptr_t)) {
6088 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6089 uintptr_t m = AsciiRangeMask(w, lo, hi);
6090 // The mask has high (7th) bit set in every byte that needs
6091 // conversion and we know that the distance between cases is
6092 // 1 << 5.
6093 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6094 src += sizeof(uintptr_t);
6095 dst += sizeof(uintptr_t);
6096 }
6097#endif
6098 // Process the last few bytes of the input (or the whole input if
6099 // unaligned access is not supported).
6100 while (src < limit) {
6101 char c = *src;
6102 if (lo < c && c < hi) {
6103 c ^= (1 << 5);
6104 changed = true;
6105 }
6106 *dst = c;
6107 ++src;
6108 ++dst;
6109 }
6110#ifdef DEBUG
6111 CheckConvert(saved_dst, saved_src, length, changed);
6112#endif
6113 return changed;
6114 }
6115
6116#ifdef DEBUG
6117 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6118 bool expected_changed = false;
6119 for (int i = 0; i < length; i++) {
6120 if (dst[i] == src[i]) continue;
6121 expected_changed = true;
6122 if (dir == ASCII_TO_LOWER) {
6123 ASSERT('A' <= src[i] && src[i] <= 'Z');
6124 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6125 } else {
6126 ASSERT(dir == ASCII_TO_UPPER);
6127 ASSERT('a' <= src[i] && src[i] <= 'z');
6128 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6129 }
6130 }
6131 ASSERT(expected_changed == changed);
6132 }
6133#endif
6134};
6135
6136
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006137struct ToLowerTraits {
6138 typedef unibrow::ToLowercase UnibrowConverter;
6139
lrn@chromium.org303ada72010-10-27 09:33:13 +00006140 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006141};
6142
6143
6144struct ToUpperTraits {
6145 typedef unibrow::ToUppercase UnibrowConverter;
6146
lrn@chromium.org303ada72010-10-27 09:33:13 +00006147 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006148};
6149
6150} // namespace
6151
6152
6153template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006154MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006155 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006156 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006157 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006158 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006159 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006160 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006161
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006162 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006163 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006164 if (length == 0) return s;
6165
6166 // Simpler handling of ascii strings.
6167 //
6168 // NOTE: This assumes that the upper/lower case of an ascii
6169 // character is also ascii. This is currently the case, but it
6170 // might break in the future if we implement more context and locale
6171 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006172 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006173 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006174 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006175 if (!maybe_o->ToObject(&o)) return maybe_o;
6176 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006177 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006178 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006179 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006180 return has_changed_character ? result : s;
6181 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006182
lrn@chromium.org303ada72010-10-27 09:33:13 +00006183 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006184 { MaybeObject* maybe_answer =
6185 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006186 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6187 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006188 if (answer->IsSmi()) {
6189 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006190 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006191 ConvertCaseHelper(isolate,
6192 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006193 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6194 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006195 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006196 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006197}
6198
6199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006200RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006201 return ConvertCase<ToLowerTraits>(
6202 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203}
6204
6205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006206RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006207 return ConvertCase<ToUpperTraits>(
6208 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006209}
6210
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006211
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006212static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006213 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006214}
6215
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006217RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006218 NoHandleAllocation ha;
6219 ASSERT(args.length() == 3);
6220
6221 CONVERT_CHECKED(String, s, args[0]);
6222 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6223 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6224
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006225 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006226 int length = s->length();
6227
6228 int left = 0;
6229 if (trimLeft) {
6230 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6231 left++;
6232 }
6233 }
6234
6235 int right = length;
6236 if (trimRight) {
6237 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6238 right--;
6239 }
6240 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006241 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006242}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006243
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006245RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006246 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006247 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006248 CONVERT_ARG_CHECKED(String, subject, 0);
6249 CONVERT_ARG_CHECKED(String, pattern, 1);
6250 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6251
6252 int subject_length = subject->length();
6253 int pattern_length = pattern->length();
6254 RUNTIME_ASSERT(pattern_length > 0);
6255
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006256 if (limit == 0xffffffffu) {
6257 Handle<Object> cached_answer(StringSplitCache::Lookup(
6258 isolate->heap()->string_split_cache(),
6259 *subject,
6260 *pattern));
6261 if (*cached_answer != Smi::FromInt(0)) {
6262 Handle<JSArray> result =
6263 isolate->factory()->NewJSArrayWithElements(
6264 Handle<FixedArray>::cast(cached_answer));
6265 return *result;
6266 }
6267 }
6268
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006269 // The limit can be very large (0xffffffffu), but since the pattern
6270 // isn't empty, we can never create more parts than ~half the length
6271 // of the subject.
6272
6273 if (!subject->IsFlat()) FlattenString(subject);
6274
6275 static const int kMaxInitialListCapacity = 16;
6276
danno@chromium.org40cb8782011-05-25 07:58:50 +00006277 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006278
6279 // Find (up to limit) indices of separator and end-of-string in subject
6280 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6281 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006282 if (!pattern->IsFlat()) FlattenString(pattern);
6283
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006284 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006285
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006286 if (static_cast<uint32_t>(indices.length()) < limit) {
6287 indices.Add(subject_length);
6288 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006289
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006290 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006291
6292 // Create JSArray of substrings separated by separator.
6293 int part_count = indices.length();
6294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006295 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006296 MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
6297 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006298 result->set_length(Smi::FromInt(part_count));
6299
6300 ASSERT(result->HasFastElements());
6301
6302 if (part_count == 1 && indices.at(0) == subject_length) {
6303 FixedArray::cast(result->elements())->set(0, *subject);
6304 return *result;
6305 }
6306
6307 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6308 int part_start = 0;
6309 for (int i = 0; i < part_count; i++) {
6310 HandleScope local_loop_handle;
6311 int part_end = indices.at(i);
6312 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006313 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006314 elements->set(i, *substring);
6315 part_start = part_end + pattern_length;
6316 }
6317
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006318 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006319 if (result->HasFastElements()) {
6320 StringSplitCache::Enter(isolate->heap(),
6321 isolate->heap()->string_split_cache(),
6322 *subject,
6323 *pattern,
6324 *elements);
6325 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006326 }
6327
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006328 return *result;
6329}
6330
6331
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006332// Copies ascii characters to the given fixed array looking up
6333// one-char strings in the cache. Gives up on the first char that is
6334// not in the cache and fills the remainder with smi zeros. Returns
6335// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006336static int CopyCachedAsciiCharsToArray(Heap* heap,
6337 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006338 FixedArray* elements,
6339 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006340 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006341 FixedArray* ascii_cache = heap->single_character_string_cache();
6342 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006343 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006344 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006345 for (i = 0; i < length; ++i) {
6346 Object* value = ascii_cache->get(chars[i]);
6347 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006348 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006349 }
6350 if (i < length) {
6351 ASSERT(Smi::FromInt(0) == 0);
6352 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6353 }
6354#ifdef DEBUG
6355 for (int j = 0; j < length; ++j) {
6356 Object* element = elements->get(j);
6357 ASSERT(element == Smi::FromInt(0) ||
6358 (element->IsString() && String::cast(element)->LooksValid()));
6359 }
6360#endif
6361 return i;
6362}
6363
6364
6365// Converts a String to JSArray.
6366// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006367RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006368 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006369 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006370 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006371 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006372
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006373 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006374 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006375
6376 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006377 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006378 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006379 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006380 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006381 { MaybeObject* maybe_obj =
6382 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006383 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6384 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006385 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006386 String::FlatContent content = s->GetFlatContent();
6387 if (content.IsAscii()) {
6388 Vector<const char> chars = content.ToAsciiVector();
6389 // Note, this will initialize all elements (not only the prefix)
6390 // to prevent GC from seeing partially initialized array.
6391 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6392 chars.start(),
6393 *elements,
6394 length);
6395 } else {
6396 MemsetPointer(elements->data_start(),
6397 isolate->heap()->undefined_value(),
6398 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006399 }
6400 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006401 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006402 }
6403 for (int i = position; i < length; ++i) {
6404 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6405 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006406 }
6407
6408#ifdef DEBUG
6409 for (int i = 0; i < length; ++i) {
6410 ASSERT(String::cast(elements->get(i))->length() == 1);
6411 }
6412#endif
6413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006414 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006415}
6416
6417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006418RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006419 NoHandleAllocation ha;
6420 ASSERT(args.length() == 1);
6421 CONVERT_CHECKED(String, value, args[0]);
6422 return value->ToObject();
6423}
6424
6425
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006426bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006427 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006428 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006429 return char_length == 0;
6430}
6431
6432
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006433RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006434 NoHandleAllocation ha;
6435 ASSERT(args.length() == 1);
6436
6437 Object* number = args[0];
6438 RUNTIME_ASSERT(number->IsNumber());
6439
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006440 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441}
6442
6443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006444RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006445 NoHandleAllocation ha;
6446 ASSERT(args.length() == 1);
6447
6448 Object* number = args[0];
6449 RUNTIME_ASSERT(number->IsNumber());
6450
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006451 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006452}
6453
6454
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006455RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006456 NoHandleAllocation ha;
6457 ASSERT(args.length() == 1);
6458
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006459 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006460
6461 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6462 if (number > 0 && number <= Smi::kMaxValue) {
6463 return Smi::FromInt(static_cast<int>(number));
6464 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006465 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006466}
6467
6468
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006469RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006470 NoHandleAllocation ha;
6471 ASSERT(args.length() == 1);
6472
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006473 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006474
6475 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6476 if (number > 0 && number <= Smi::kMaxValue) {
6477 return Smi::FromInt(static_cast<int>(number));
6478 }
6479
6480 double double_value = DoubleToInteger(number);
6481 // Map both -0 and +0 to +0.
6482 if (double_value == 0) double_value = 0;
6483
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006484 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006485}
6486
6487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006488RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006489 NoHandleAllocation ha;
6490 ASSERT(args.length() == 1);
6491
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006492 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006493 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006494}
6495
6496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006497RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006498 NoHandleAllocation ha;
6499 ASSERT(args.length() == 1);
6500
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006501 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006502
6503 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6504 if (number > 0 && number <= Smi::kMaxValue) {
6505 return Smi::FromInt(static_cast<int>(number));
6506 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006507 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006508}
6509
6510
ager@chromium.org870a0b62008-11-04 11:43:05 +00006511// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6512// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006513RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006514 NoHandleAllocation ha;
6515 ASSERT(args.length() == 1);
6516
6517 Object* obj = args[0];
6518 if (obj->IsSmi()) {
6519 return obj;
6520 }
6521 if (obj->IsHeapNumber()) {
6522 double value = HeapNumber::cast(obj)->value();
6523 int int_value = FastD2I(value);
6524 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6525 return Smi::FromInt(int_value);
6526 }
6527 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006528 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006529}
6530
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006531
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006532RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006533 NoHandleAllocation ha;
6534 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006535 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006536}
6537
6538
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006539RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006540 NoHandleAllocation ha;
6541 ASSERT(args.length() == 2);
6542
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006543 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6544 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006545 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006546}
6547
6548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006549RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550 NoHandleAllocation ha;
6551 ASSERT(args.length() == 2);
6552
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006553 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6554 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006555 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006556}
6557
6558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006559RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006560 NoHandleAllocation ha;
6561 ASSERT(args.length() == 2);
6562
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006563 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6564 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006565 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566}
6567
6568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006569RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006570 NoHandleAllocation ha;
6571 ASSERT(args.length() == 1);
6572
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006573 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006574 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575}
6576
6577
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006578RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006579 NoHandleAllocation ha;
6580 ASSERT(args.length() == 0);
6581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006582 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006583}
6584
6585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006586RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
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_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006597 NoHandleAllocation ha;
6598 ASSERT(args.length() == 2);
6599
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006600 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6601 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006602
ager@chromium.org3811b432009-10-28 14:53:37 +00006603 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006604 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006605 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006606}
6607
6608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006609RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610 NoHandleAllocation ha;
6611 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006612 CONVERT_CHECKED(String, str1, args[0]);
6613 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006614 isolate->counters()->string_add_runtime()->Increment();
6615 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616}
6617
6618
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006619template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006620static inline void StringBuilderConcatHelper(String* special,
6621 sinkchar* sink,
6622 FixedArray* fixed_array,
6623 int array_length) {
6624 int position = 0;
6625 for (int i = 0; i < array_length; i++) {
6626 Object* element = fixed_array->get(i);
6627 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006628 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006629 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006630 int pos;
6631 int len;
6632 if (encoded_slice > 0) {
6633 // Position and length encoded in one smi.
6634 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6635 len = StringBuilderSubstringLength::decode(encoded_slice);
6636 } else {
6637 // Position and length encoded in two smis.
6638 Object* obj = fixed_array->get(++i);
6639 ASSERT(obj->IsSmi());
6640 pos = Smi::cast(obj)->value();
6641 len = -encoded_slice;
6642 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006643 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006644 sink + position,
6645 pos,
6646 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006647 position += len;
6648 } else {
6649 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006650 int element_length = string->length();
6651 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006652 position += element_length;
6653 }
6654 }
6655}
6656
6657
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006658RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006659 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006660 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006662 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006663 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006664 return Failure::OutOfMemoryException();
6665 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006666 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006667 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006668
6669 // This assumption is used by the slice encoding in one or two smis.
6670 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6671
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006672 MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
6673 if (maybe_result->IsFailure()) return maybe_result;
6674
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006675 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006676 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006677 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006678 }
6679 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006680 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006681 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006682 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006683
6684 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006685 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686 } else if (array_length == 1) {
6687 Object* first = fixed_array->get(0);
6688 if (first->IsString()) return first;
6689 }
6690
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006691 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006692 int position = 0;
6693 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006694 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006695 Object* elt = fixed_array->get(i);
6696 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006697 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006698 int smi_value = Smi::cast(elt)->value();
6699 int pos;
6700 int len;
6701 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006702 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006703 pos = StringBuilderSubstringPosition::decode(smi_value);
6704 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006705 } else {
6706 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006707 len = -smi_value;
6708 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006709 i++;
6710 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006711 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006712 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006713 Object* next_smi = fixed_array->get(i);
6714 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006715 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006716 }
6717 pos = Smi::cast(next_smi)->value();
6718 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006719 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006720 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006721 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006722 ASSERT(pos >= 0);
6723 ASSERT(len >= 0);
6724 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006725 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006726 }
6727 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 } else if (elt->IsString()) {
6729 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006730 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006731 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006732 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006733 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006734 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006736 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006738 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006739 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006740 return Failure::OutOfMemoryException();
6741 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006742 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006743 }
6744
6745 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006746 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006747
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006748 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006749 { MaybeObject* maybe_object =
6750 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006751 if (!maybe_object->ToObject(&object)) return maybe_object;
6752 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006753 SeqAsciiString* answer = SeqAsciiString::cast(object);
6754 StringBuilderConcatHelper(special,
6755 answer->GetChars(),
6756 fixed_array,
6757 array_length);
6758 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006759 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006760 { MaybeObject* maybe_object =
6761 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006762 if (!maybe_object->ToObject(&object)) return maybe_object;
6763 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006764 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6765 StringBuilderConcatHelper(special,
6766 answer->GetChars(),
6767 fixed_array,
6768 array_length);
6769 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006771}
6772
6773
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006774RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006775 NoHandleAllocation ha;
6776 ASSERT(args.length() == 3);
6777 CONVERT_CHECKED(JSArray, array, args[0]);
6778 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006779 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006780 return Failure::OutOfMemoryException();
6781 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006782 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006783 CONVERT_CHECKED(String, separator, args[2]);
6784
6785 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006786 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006787 }
6788 FixedArray* fixed_array = FixedArray::cast(array->elements());
6789 if (fixed_array->length() < array_length) {
6790 array_length = fixed_array->length();
6791 }
6792
6793 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006794 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006795 } else if (array_length == 1) {
6796 Object* first = fixed_array->get(0);
6797 if (first->IsString()) return first;
6798 }
6799
6800 int separator_length = separator->length();
6801 int max_nof_separators =
6802 (String::kMaxLength + separator_length - 1) / separator_length;
6803 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006804 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006805 return Failure::OutOfMemoryException();
6806 }
6807 int length = (array_length - 1) * separator_length;
6808 for (int i = 0; i < array_length; i++) {
6809 Object* element_obj = fixed_array->get(i);
6810 if (!element_obj->IsString()) {
6811 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006812 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006813 }
6814 String* element = String::cast(element_obj);
6815 int increment = element->length();
6816 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006817 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006818 return Failure::OutOfMemoryException();
6819 }
6820 length += increment;
6821 }
6822
6823 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006824 { MaybeObject* maybe_object =
6825 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006826 if (!maybe_object->ToObject(&object)) return maybe_object;
6827 }
6828 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6829
6830 uc16* sink = answer->GetChars();
6831#ifdef DEBUG
6832 uc16* end = sink + length;
6833#endif
6834
6835 String* first = String::cast(fixed_array->get(0));
6836 int first_length = first->length();
6837 String::WriteToFlat(first, sink, 0, first_length);
6838 sink += first_length;
6839
6840 for (int i = 1; i < array_length; i++) {
6841 ASSERT(sink + separator_length <= end);
6842 String::WriteToFlat(separator, sink, 0, separator_length);
6843 sink += separator_length;
6844
6845 String* element = String::cast(fixed_array->get(i));
6846 int element_length = element->length();
6847 ASSERT(sink + element_length <= end);
6848 String::WriteToFlat(element, sink, 0, element_length);
6849 sink += element_length;
6850 }
6851 ASSERT(sink == end);
6852
6853 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6854 return answer;
6855}
6856
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006857template <typename Char>
6858static void JoinSparseArrayWithSeparator(FixedArray* elements,
6859 int elements_length,
6860 uint32_t array_length,
6861 String* separator,
6862 Vector<Char> buffer) {
6863 int previous_separator_position = 0;
6864 int separator_length = separator->length();
6865 int cursor = 0;
6866 for (int i = 0; i < elements_length; i += 2) {
6867 int position = NumberToInt32(elements->get(i));
6868 String* string = String::cast(elements->get(i + 1));
6869 int string_length = string->length();
6870 if (string->length() > 0) {
6871 while (previous_separator_position < position) {
6872 String::WriteToFlat<Char>(separator, &buffer[cursor],
6873 0, separator_length);
6874 cursor += separator_length;
6875 previous_separator_position++;
6876 }
6877 String::WriteToFlat<Char>(string, &buffer[cursor],
6878 0, string_length);
6879 cursor += string->length();
6880 }
6881 }
6882 if (separator_length > 0) {
6883 // Array length must be representable as a signed 32-bit number,
6884 // otherwise the total string length would have been too large.
6885 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6886 int last_array_index = static_cast<int>(array_length - 1);
6887 while (previous_separator_position < last_array_index) {
6888 String::WriteToFlat<Char>(separator, &buffer[cursor],
6889 0, separator_length);
6890 cursor += separator_length;
6891 previous_separator_position++;
6892 }
6893 }
6894 ASSERT(cursor <= buffer.length());
6895}
6896
6897
6898RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6899 NoHandleAllocation ha;
6900 ASSERT(args.length() == 3);
6901 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006902 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6903 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006904 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6905 CONVERT_CHECKED(String, separator, args[2]);
6906 // elements_array is fast-mode JSarray of alternating positions
6907 // (increasing order) and strings.
6908 // array_length is length of original array (used to add separators);
6909 // separator is string to put between elements. Assumed to be non-empty.
6910
6911 // Find total length of join result.
6912 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006913 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006914 int max_string_length;
6915 if (is_ascii) {
6916 max_string_length = SeqAsciiString::kMaxLength;
6917 } else {
6918 max_string_length = SeqTwoByteString::kMaxLength;
6919 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006920 bool overflow = false;
6921 CONVERT_NUMBER_CHECKED(int, elements_length,
6922 Int32, elements_array->length());
6923 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6924 FixedArray* elements = FixedArray::cast(elements_array->elements());
6925 for (int i = 0; i < elements_length; i += 2) {
6926 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6927 CONVERT_CHECKED(String, string, elements->get(i + 1));
6928 int length = string->length();
6929 if (is_ascii && !string->IsAsciiRepresentation()) {
6930 is_ascii = false;
6931 max_string_length = SeqTwoByteString::kMaxLength;
6932 }
6933 if (length > max_string_length ||
6934 max_string_length - length < string_length) {
6935 overflow = true;
6936 break;
6937 }
6938 string_length += length;
6939 }
6940 int separator_length = separator->length();
6941 if (!overflow && separator_length > 0) {
6942 if (array_length <= 0x7fffffffu) {
6943 int separator_count = static_cast<int>(array_length) - 1;
6944 int remaining_length = max_string_length - string_length;
6945 if ((remaining_length / separator_length) >= separator_count) {
6946 string_length += separator_length * (array_length - 1);
6947 } else {
6948 // Not room for the separators within the maximal string length.
6949 overflow = true;
6950 }
6951 } else {
6952 // Nonempty separator and at least 2^31-1 separators necessary
6953 // means that the string is too large to create.
6954 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6955 overflow = true;
6956 }
6957 }
6958 if (overflow) {
6959 // Throw OutOfMemory exception for creating too large a string.
6960 V8::FatalProcessOutOfMemory("Array join result too large.");
6961 }
6962
6963 if (is_ascii) {
6964 MaybeObject* result_allocation =
6965 isolate->heap()->AllocateRawAsciiString(string_length);
6966 if (result_allocation->IsFailure()) return result_allocation;
6967 SeqAsciiString* result_string =
6968 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6969 JoinSparseArrayWithSeparator<char>(elements,
6970 elements_length,
6971 array_length,
6972 separator,
6973 Vector<char>(result_string->GetChars(),
6974 string_length));
6975 return result_string;
6976 } else {
6977 MaybeObject* result_allocation =
6978 isolate->heap()->AllocateRawTwoByteString(string_length);
6979 if (result_allocation->IsFailure()) return result_allocation;
6980 SeqTwoByteString* result_string =
6981 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6982 JoinSparseArrayWithSeparator<uc16>(elements,
6983 elements_length,
6984 array_length,
6985 separator,
6986 Vector<uc16>(result_string->GetChars(),
6987 string_length));
6988 return result_string;
6989 }
6990}
6991
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006993RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006994 NoHandleAllocation ha;
6995 ASSERT(args.length() == 2);
6996
6997 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6998 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006999 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007000}
7001
7002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007003RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007004 NoHandleAllocation ha;
7005 ASSERT(args.length() == 2);
7006
7007 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7008 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007009 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007010}
7011
7012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007013RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007014 NoHandleAllocation ha;
7015 ASSERT(args.length() == 2);
7016
7017 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7018 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007019 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007020}
7021
7022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007023RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007024 NoHandleAllocation ha;
7025 ASSERT(args.length() == 1);
7026
7027 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007028 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029}
7030
7031
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007032RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007033 NoHandleAllocation ha;
7034 ASSERT(args.length() == 2);
7035
7036 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7037 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007038 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007039}
7040
7041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007042RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043 NoHandleAllocation ha;
7044 ASSERT(args.length() == 2);
7045
7046 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7047 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007048 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007049}
7050
7051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007052RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053 NoHandleAllocation ha;
7054 ASSERT(args.length() == 2);
7055
7056 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7057 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007058 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007059}
7060
7061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007062RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007063 NoHandleAllocation ha;
7064 ASSERT(args.length() == 2);
7065
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007066 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7067 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7069 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7070 if (x == y) return Smi::FromInt(EQUAL);
7071 Object* result;
7072 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7073 result = Smi::FromInt(EQUAL);
7074 } else {
7075 result = Smi::FromInt(NOT_EQUAL);
7076 }
7077 return result;
7078}
7079
7080
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007081RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007082 NoHandleAllocation ha;
7083 ASSERT(args.length() == 2);
7084
7085 CONVERT_CHECKED(String, x, args[0]);
7086 CONVERT_CHECKED(String, y, args[1]);
7087
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007088 bool not_equal = !x->Equals(y);
7089 // This is slightly convoluted because the value that signifies
7090 // equality is 0 and inequality is 1 so we have to negate the result
7091 // from String::Equals.
7092 ASSERT(not_equal == 0 || not_equal == 1);
7093 STATIC_CHECK(EQUAL == 0);
7094 STATIC_CHECK(NOT_EQUAL == 1);
7095 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007096}
7097
7098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007099RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100 NoHandleAllocation ha;
7101 ASSERT(args.length() == 3);
7102
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007103 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7104 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007105 if (isnan(x) || isnan(y)) return args[2];
7106 if (x == y) return Smi::FromInt(EQUAL);
7107 if (isless(x, y)) return Smi::FromInt(LESS);
7108 return Smi::FromInt(GREATER);
7109}
7110
7111
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007112// Compare two Smis as if they were converted to strings and then
7113// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007114RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007115 NoHandleAllocation ha;
7116 ASSERT(args.length() == 2);
7117
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007118 // Extract the integer values from the Smis.
7119 CONVERT_CHECKED(Smi, x, args[0]);
7120 CONVERT_CHECKED(Smi, y, args[1]);
7121 int x_value = x->value();
7122 int y_value = y->value();
7123
7124 // If the integers are equal so are the string representations.
7125 if (x_value == y_value) return Smi::FromInt(EQUAL);
7126
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007127 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007128 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007129 if (x_value == 0 || y_value == 0)
7130 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007131
ager@chromium.org32912102009-01-16 10:38:43 +00007132 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007133 // smallest because the char code of '-' is less than the char code
7134 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007135
7136 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7137 // architectures using 32-bit Smis.
7138 uint32_t x_scaled = x_value;
7139 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007140 if (x_value < 0 || y_value < 0) {
7141 if (y_value >= 0) return Smi::FromInt(LESS);
7142 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007143 x_scaled = -x_value;
7144 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007145 }
7146
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007147 static const uint32_t kPowersOf10[] = {
7148 1, 10, 100, 1000, 10*1000, 100*1000,
7149 1000*1000, 10*1000*1000, 100*1000*1000,
7150 1000*1000*1000
7151 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007152
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007153 // If the integers have the same number of decimal digits they can be
7154 // compared directly as the numeric order is the same as the
7155 // lexicographic order. If one integer has fewer digits, it is scaled
7156 // by some power of 10 to have the same number of digits as the longer
7157 // integer. If the scaled integers are equal it means the shorter
7158 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007159
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007160 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7161 int x_log2 = IntegerLog2(x_scaled);
7162 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7163 x_log10 -= x_scaled < kPowersOf10[x_log10];
7164
7165 int y_log2 = IntegerLog2(y_scaled);
7166 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7167 y_log10 -= y_scaled < kPowersOf10[y_log10];
7168
7169 int tie = EQUAL;
7170
7171 if (x_log10 < y_log10) {
7172 // X has fewer digits. We would like to simply scale up X but that
7173 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7174 // be scaled up to 9_000_000_000. So we scale up by the next
7175 // smallest power and scale down Y to drop one digit. It is OK to
7176 // drop one digit from the longer integer since the final digit is
7177 // past the length of the shorter integer.
7178 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7179 y_scaled /= 10;
7180 tie = LESS;
7181 } else if (y_log10 < x_log10) {
7182 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7183 x_scaled /= 10;
7184 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007185 }
7186
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007187 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7188 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7189 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007190}
7191
7192
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007193static Object* StringInputBufferCompare(RuntimeState* state,
7194 String* x,
7195 String* y) {
7196 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7197 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007198 bufx.Reset(x);
7199 bufy.Reset(y);
7200 while (bufx.has_more() && bufy.has_more()) {
7201 int d = bufx.GetNext() - bufy.GetNext();
7202 if (d < 0) return Smi::FromInt(LESS);
7203 else if (d > 0) return Smi::FromInt(GREATER);
7204 }
7205
7206 // x is (non-trivial) prefix of y:
7207 if (bufy.has_more()) return Smi::FromInt(LESS);
7208 // y is prefix of x:
7209 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7210}
7211
7212
7213static Object* FlatStringCompare(String* x, String* y) {
7214 ASSERT(x->IsFlat());
7215 ASSERT(y->IsFlat());
7216 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7217 int prefix_length = x->length();
7218 if (y->length() < prefix_length) {
7219 prefix_length = y->length();
7220 equal_prefix_result = Smi::FromInt(GREATER);
7221 } else if (y->length() > prefix_length) {
7222 equal_prefix_result = Smi::FromInt(LESS);
7223 }
7224 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007225 String::FlatContent x_content = x->GetFlatContent();
7226 String::FlatContent y_content = y->GetFlatContent();
7227 if (x_content.IsAscii()) {
7228 Vector<const char> x_chars = x_content.ToAsciiVector();
7229 if (y_content.IsAscii()) {
7230 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007231 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007232 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007233 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007234 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7235 }
7236 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007237 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7238 if (y_content.IsAscii()) {
7239 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007240 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7241 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007242 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007243 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7244 }
7245 }
7246 Object* result;
7247 if (r == 0) {
7248 result = equal_prefix_result;
7249 } else {
7250 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7251 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007252 ASSERT(result ==
7253 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007254 return result;
7255}
7256
7257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007258RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007259 NoHandleAllocation ha;
7260 ASSERT(args.length() == 2);
7261
7262 CONVERT_CHECKED(String, x, args[0]);
7263 CONVERT_CHECKED(String, y, args[1]);
7264
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007265 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007267 // A few fast case tests before we flatten.
7268 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007269 if (y->length() == 0) {
7270 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007271 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007272 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007273 return Smi::FromInt(LESS);
7274 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007275
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007276 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007277 if (d < 0) return Smi::FromInt(LESS);
7278 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007279
lrn@chromium.org303ada72010-10-27 09:33:13 +00007280 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007281 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007282 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7283 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007284 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007285 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7286 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007287
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007288 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007289 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290}
7291
7292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007293RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294 NoHandleAllocation ha;
7295 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007296 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007297
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007298 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007299 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007300}
7301
7302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007303RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007304 NoHandleAllocation ha;
7305 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007306 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007307
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007308 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007309 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007310}
7311
7312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007313RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314 NoHandleAllocation ha;
7315 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007316 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007317
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007318 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007319 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007320}
7321
7322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007323static const double kPiDividedBy4 = 0.78539816339744830962;
7324
7325
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007326RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007327 NoHandleAllocation ha;
7328 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007329 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007330
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007331 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7332 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007333 double result;
7334 if (isinf(x) && isinf(y)) {
7335 // Make sure that the result in case of two infinite arguments
7336 // is a multiple of Pi / 4. The sign of the result is determined
7337 // by the first argument (x) and the sign of the second argument
7338 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339 int multiplier = (x < 0) ? -1 : 1;
7340 if (y < 0) multiplier *= 3;
7341 result = multiplier * kPiDividedBy4;
7342 } else {
7343 result = atan2(x, y);
7344 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007345 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346}
7347
7348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007349RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007350 NoHandleAllocation ha;
7351 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007352 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007353
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007354 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007355 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356}
7357
7358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007359RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007360 NoHandleAllocation ha;
7361 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007362 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007364 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007365 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007366}
7367
7368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007369RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370 NoHandleAllocation ha;
7371 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007372 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007374 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007375 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007376}
7377
7378
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007379RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380 NoHandleAllocation ha;
7381 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007382 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007383
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007384 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007385 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007386}
7387
7388
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007389RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390 NoHandleAllocation ha;
7391 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007392 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007394 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007395 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007396}
7397
7398
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007399RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400 NoHandleAllocation ha;
7401 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007402 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007404 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007405
7406 // If the second argument is a smi, it is much faster to call the
7407 // custom powi() function than the generic pow().
7408 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007409 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007410 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007411 }
7412
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007413 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007414 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007415}
7416
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007417// Fast version of Math.pow if we know that y is not an integer and
7418// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007419RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007420 NoHandleAllocation ha;
7421 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007422 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7423 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007424 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007425 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007426 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007427 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007428 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007429 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007430 }
7431}
7432
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007434RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007435 NoHandleAllocation ha;
7436 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007437 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007438
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007439 if (!args[0]->IsHeapNumber()) {
7440 // Must be smi. Return the argument unchanged for all the other types
7441 // to make fuzz-natives test happy.
7442 return args[0];
7443 }
7444
7445 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7446
7447 double value = number->value();
7448 int exponent = number->get_exponent();
7449 int sign = number->get_sign();
7450
danno@chromium.org160a7b02011-04-18 15:51:38 +00007451 if (exponent < -1) {
7452 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7453 if (sign) return isolate->heap()->minus_zero_value();
7454 return Smi::FromInt(0);
7455 }
7456
7457 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7458 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7459 // agument holds for 32-bit smis).
7460 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007461 return Smi::FromInt(static_cast<int>(value + 0.5));
7462 }
7463
7464 // If the magnitude is big enough, there's no place for fraction part. If we
7465 // try to add 0.5 to this number, 1.0 will be added instead.
7466 if (exponent >= 52) {
7467 return number;
7468 }
7469
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007470 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007471
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007472 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007473 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007474}
7475
7476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007477RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007478 NoHandleAllocation ha;
7479 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007480 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007481
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007482 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007483 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007484}
7485
7486
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007487RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007488 NoHandleAllocation ha;
7489 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007490 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007491
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007492 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007493 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007494}
7495
7496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007497RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007498 NoHandleAllocation ha;
7499 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007500 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007501
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007502 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007503 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007504}
7505
7506
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007507static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007508 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7509 181, 212, 243, 273, 304, 334};
7510 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7511 182, 213, 244, 274, 305, 335};
7512
7513 year += month / 12;
7514 month %= 12;
7515 if (month < 0) {
7516 year--;
7517 month += 12;
7518 }
7519
7520 ASSERT(month >= 0);
7521 ASSERT(month < 12);
7522
7523 // year_delta is an arbitrary number such that:
7524 // a) year_delta = -1 (mod 400)
7525 // b) year + year_delta > 0 for years in the range defined by
7526 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7527 // Jan 1 1970. This is required so that we don't run into integer
7528 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007529 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007530 // operations.
7531 static const int year_delta = 399999;
7532 static const int base_day = 365 * (1970 + year_delta) +
7533 (1970 + year_delta) / 4 -
7534 (1970 + year_delta) / 100 +
7535 (1970 + year_delta) / 400;
7536
7537 int year1 = year + year_delta;
7538 int day_from_year = 365 * year1 +
7539 year1 / 4 -
7540 year1 / 100 +
7541 year1 / 400 -
7542 base_day;
7543
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007544 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7545 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007546 }
7547
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007548 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007549}
7550
7551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007552RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007553 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007554 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007555
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007556 CONVERT_SMI_ARG_CHECKED(year, 0);
7557 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007558
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007559 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007560}
7561
7562
7563static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7564static const int kDaysIn4Years = 4 * 365 + 1;
7565static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7566static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7567static const int kDays1970to2000 = 30 * 365 + 7;
7568static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7569 kDays1970to2000;
7570static const int kYearsOffset = 400000;
7571
7572static const char kDayInYear[] = {
7573 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7574 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7575 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7576 22, 23, 24, 25, 26, 27, 28,
7577 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7578 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7579 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7580 22, 23, 24, 25, 26, 27, 28, 29, 30,
7581 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7582 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7583 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7584 22, 23, 24, 25, 26, 27, 28, 29, 30,
7585 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7586 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7587 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7588 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7589 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7590 22, 23, 24, 25, 26, 27, 28, 29, 30,
7591 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7592 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7593 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7594 22, 23, 24, 25, 26, 27, 28, 29, 30,
7595 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7596 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7597
7598 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7599 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7600 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7601 22, 23, 24, 25, 26, 27, 28,
7602 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7603 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7604 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7605 22, 23, 24, 25, 26, 27, 28, 29, 30,
7606 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7607 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7608 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7609 22, 23, 24, 25, 26, 27, 28, 29, 30,
7610 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7611 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7612 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7613 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7614 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7615 22, 23, 24, 25, 26, 27, 28, 29, 30,
7616 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7617 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7618 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7619 22, 23, 24, 25, 26, 27, 28, 29, 30,
7620 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7621 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7622
7623 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7624 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7625 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7626 22, 23, 24, 25, 26, 27, 28, 29,
7627 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7628 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7629 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7630 22, 23, 24, 25, 26, 27, 28, 29, 30,
7631 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7632 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7633 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7634 22, 23, 24, 25, 26, 27, 28, 29, 30,
7635 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7636 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7637 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7638 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7639 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7640 22, 23, 24, 25, 26, 27, 28, 29, 30,
7641 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7642 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7643 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7644 22, 23, 24, 25, 26, 27, 28, 29, 30,
7645 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7646 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7647
7648 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7649 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7650 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7651 22, 23, 24, 25, 26, 27, 28,
7652 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7653 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7654 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7655 22, 23, 24, 25, 26, 27, 28, 29, 30,
7656 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7657 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7658 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7659 22, 23, 24, 25, 26, 27, 28, 29, 30,
7660 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7661 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7662 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7663 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7664 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7665 22, 23, 24, 25, 26, 27, 28, 29, 30,
7666 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7667 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7668 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7669 22, 23, 24, 25, 26, 27, 28, 29, 30,
7670 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7671 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7672
7673static const char kMonthInYear[] = {
7674 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7675 0, 0, 0, 0, 0, 0,
7676 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7677 1, 1, 1,
7678 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7679 2, 2, 2, 2, 2, 2,
7680 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7681 3, 3, 3, 3, 3,
7682 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7683 4, 4, 4, 4, 4, 4,
7684 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7685 5, 5, 5, 5, 5,
7686 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7687 6, 6, 6, 6, 6, 6,
7688 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7689 7, 7, 7, 7, 7, 7,
7690 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7691 8, 8, 8, 8, 8,
7692 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7693 9, 9, 9, 9, 9, 9,
7694 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7695 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7696 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7697 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7698
7699 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7700 0, 0, 0, 0, 0, 0,
7701 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7702 1, 1, 1,
7703 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7704 2, 2, 2, 2, 2, 2,
7705 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7706 3, 3, 3, 3, 3,
7707 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7708 4, 4, 4, 4, 4, 4,
7709 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7710 5, 5, 5, 5, 5,
7711 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7712 6, 6, 6, 6, 6, 6,
7713 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7714 7, 7, 7, 7, 7, 7,
7715 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7716 8, 8, 8, 8, 8,
7717 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7718 9, 9, 9, 9, 9, 9,
7719 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7720 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7721 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7722 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7723
7724 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7725 0, 0, 0, 0, 0, 0,
7726 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7727 1, 1, 1, 1,
7728 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7729 2, 2, 2, 2, 2, 2,
7730 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7731 3, 3, 3, 3, 3,
7732 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7733 4, 4, 4, 4, 4, 4,
7734 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7735 5, 5, 5, 5, 5,
7736 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7737 6, 6, 6, 6, 6, 6,
7738 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7739 7, 7, 7, 7, 7, 7,
7740 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7741 8, 8, 8, 8, 8,
7742 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7743 9, 9, 9, 9, 9, 9,
7744 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7745 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7746 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7747 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7748
7749 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7750 0, 0, 0, 0, 0, 0,
7751 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7752 1, 1, 1,
7753 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7754 2, 2, 2, 2, 2, 2,
7755 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7756 3, 3, 3, 3, 3,
7757 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7758 4, 4, 4, 4, 4, 4,
7759 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7760 5, 5, 5, 5, 5,
7761 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7762 6, 6, 6, 6, 6, 6,
7763 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7764 7, 7, 7, 7, 7, 7,
7765 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7766 8, 8, 8, 8, 8,
7767 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7768 9, 9, 9, 9, 9, 9,
7769 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7770 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7771 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7772 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7773
7774
7775// This function works for dates from 1970 to 2099.
7776static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007777 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007778#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007779 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007780#endif
7781
7782 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7783 date %= kDaysIn4Years;
7784
7785 month = kMonthInYear[date];
7786 day = kDayInYear[date];
7787
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007788 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007789}
7790
7791
7792static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007793 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007794#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007795 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007796#endif
7797
7798 date += kDaysOffset;
7799 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7800 date %= kDaysIn400Years;
7801
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007802 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007803
7804 date--;
7805 int yd1 = date / kDaysIn100Years;
7806 date %= kDaysIn100Years;
7807 year += 100 * yd1;
7808
7809 date++;
7810 int yd2 = date / kDaysIn4Years;
7811 date %= kDaysIn4Years;
7812 year += 4 * yd2;
7813
7814 date--;
7815 int yd3 = date / 365;
7816 date %= 365;
7817 year += yd3;
7818
7819 bool is_leap = (!yd1 || yd2) && !yd3;
7820
7821 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007822 ASSERT(is_leap || (date >= 0));
7823 ASSERT((date < 365) || (is_leap && (date < 366)));
7824 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007825 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7826 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007827
7828 if (is_leap) {
7829 day = kDayInYear[2*365 + 1 + date];
7830 month = kMonthInYear[2*365 + 1 + date];
7831 } else {
7832 day = kDayInYear[date];
7833 month = kMonthInYear[date];
7834 }
7835
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007836 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007837}
7838
7839
7840static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007841 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007842 if (date >= 0 && date < 32 * kDaysIn4Years) {
7843 DateYMDFromTimeAfter1970(date, year, month, day);
7844 } else {
7845 DateYMDFromTimeSlow(date, year, month, day);
7846 }
7847}
7848
7849
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007850RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007851 NoHandleAllocation ha;
7852 ASSERT(args.length() == 2);
7853
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007854 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007855 CONVERT_CHECKED(JSArray, res_array, args[1]);
7856
7857 int year, month, day;
7858 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7859
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007860 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7861 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007862 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007863
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007864 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7865 if (maybe->IsFailure()) return maybe;
7866 FixedArray* elms = FixedArray::cast(res_array->elements());
7867 elms->set(0, Smi::FromInt(year));
7868 elms->set(1, Smi::FromInt(month));
7869 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007871 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007872}
7873
7874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007875RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007876 HandleScope scope(isolate);
7877 ASSERT(args.length() == 3);
7878
7879 Handle<JSFunction> callee = args.at<JSFunction>(0);
7880 Object** parameters = reinterpret_cast<Object**>(args[1]);
7881 const int argument_count = Smi::cast(args[2])->value();
7882
7883 Handle<JSObject> result =
7884 isolate->factory()->NewArgumentsObject(callee, argument_count);
7885 // Allocate the elements if needed.
7886 int parameter_count = callee->shared()->formal_parameter_count();
7887 if (argument_count > 0) {
7888 if (parameter_count > 0) {
7889 int mapped_count = Min(argument_count, parameter_count);
7890 Handle<FixedArray> parameter_map =
7891 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7892 parameter_map->set_map(
7893 isolate->heap()->non_strict_arguments_elements_map());
7894
7895 Handle<Map> old_map(result->map());
7896 Handle<Map> new_map =
7897 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007898 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007899
7900 result->set_map(*new_map);
7901 result->set_elements(*parameter_map);
7902
7903 // Store the context and the arguments array at the beginning of the
7904 // parameter map.
7905 Handle<Context> context(isolate->context());
7906 Handle<FixedArray> arguments =
7907 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7908 parameter_map->set(0, *context);
7909 parameter_map->set(1, *arguments);
7910
7911 // Loop over the actual parameters backwards.
7912 int index = argument_count - 1;
7913 while (index >= mapped_count) {
7914 // These go directly in the arguments array and have no
7915 // corresponding slot in the parameter map.
7916 arguments->set(index, *(parameters - index - 1));
7917 --index;
7918 }
7919
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007920 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007921 while (index >= 0) {
7922 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007923 Handle<String> name(scope_info->ParameterName(index));
7924 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007925 bool duplicate = false;
7926 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007927 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007928 duplicate = true;
7929 break;
7930 }
7931 }
7932
7933 if (duplicate) {
7934 // This goes directly in the arguments array with a hole in the
7935 // parameter map.
7936 arguments->set(index, *(parameters - index - 1));
7937 parameter_map->set_the_hole(index + 2);
7938 } else {
7939 // The context index goes in the parameter map with a hole in the
7940 // arguments array.
7941 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007942 for (int j = 0; j < context_local_count; ++j) {
7943 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007944 context_index = j;
7945 break;
7946 }
7947 }
7948 ASSERT(context_index >= 0);
7949 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007950 parameter_map->set(index + 2, Smi::FromInt(
7951 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007952 }
7953
7954 --index;
7955 }
7956 } else {
7957 // If there is no aliasing, the arguments object elements are not
7958 // special in any way.
7959 Handle<FixedArray> elements =
7960 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7961 result->set_elements(*elements);
7962 for (int i = 0; i < argument_count; ++i) {
7963 elements->set(i, *(parameters - i - 1));
7964 }
7965 }
7966 }
7967 return *result;
7968}
7969
7970
7971RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007972 NoHandleAllocation ha;
7973 ASSERT(args.length() == 3);
7974
7975 JSFunction* callee = JSFunction::cast(args[0]);
7976 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007977 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007978
lrn@chromium.org303ada72010-10-27 09:33:13 +00007979 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007980 { MaybeObject* maybe_result =
7981 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007982 if (!maybe_result->ToObject(&result)) return maybe_result;
7983 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007984 // Allocate the elements if needed.
7985 if (length > 0) {
7986 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007987 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007988 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007989 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7990 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007991
7992 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007993 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007994 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007995 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007996
7997 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007998 for (int i = 0; i < length; i++) {
7999 array->set(i, *--parameters, mode);
8000 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008001 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008002 }
8003 return result;
8004}
8005
8006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008007RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008008 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008009 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008010 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008011 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008012 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008013
whesse@chromium.org7b260152011-06-20 15:33:18 +00008014 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008015 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008016 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008017 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008018 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8019 context,
8020 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008021 return *result;
8022}
8023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008024
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008025// Find the arguments of the JavaScript function invocation that called
8026// into C++ code. Collect these in a newly allocated array of handles (possibly
8027// prefixed by a number of empty handles).
8028static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8029 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008030 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008031 // Find frame containing arguments passed to the caller.
8032 JavaScriptFrameIterator it;
8033 JavaScriptFrame* frame = it.frame();
8034 List<JSFunction*> functions(2);
8035 frame->GetFunctions(&functions);
8036 if (functions.length() > 1) {
8037 int inlined_frame_index = functions.length() - 1;
8038 JSFunction* inlined_function = functions[inlined_frame_index];
8039 int args_count = inlined_function->shared()->formal_parameter_count();
8040 ScopedVector<SlotRef> args_slots(args_count);
8041 SlotRef::ComputeSlotMappingForArguments(frame,
8042 inlined_frame_index,
8043 &args_slots);
8044
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008045 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008046 SmartArrayPointer<Handle<Object> > param_data(
8047 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008048 for (int i = 0; i < args_count; i++) {
8049 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008050 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008051 }
8052 return param_data;
8053 } else {
8054 it.AdvanceToArgumentsFrame();
8055 frame = it.frame();
8056 int args_count = frame->ComputeParametersCount();
8057
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008058 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008059 SmartArrayPointer<Handle<Object> > param_data(
8060 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008061 for (int i = 0; i < args_count; i++) {
8062 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008063 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008064 }
8065 return param_data;
8066 }
8067}
8068
8069
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008070RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8071 HandleScope scope(isolate);
8072 ASSERT(args.length() == 4);
8073 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8074 RUNTIME_ASSERT(args[3]->IsNumber());
8075 Handle<Object> bindee = args.at<Object>(1);
8076
8077 // TODO(lrn): Create bound function in C++ code from premade shared info.
8078 bound_function->shared()->set_bound(true);
8079 // Get all arguments of calling function (Function.prototype.bind).
8080 int argc = 0;
8081 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8082 // Don't count the this-arg.
8083 if (argc > 0) {
8084 ASSERT(*arguments[0] == args[2]);
8085 argc--;
8086 } else {
8087 ASSERT(args[2]->IsUndefined());
8088 }
8089 // Initialize array of bindings (function, this, and any existing arguments
8090 // if the function was already bound).
8091 Handle<FixedArray> new_bindings;
8092 int i;
8093 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8094 Handle<FixedArray> old_bindings(
8095 JSFunction::cast(*bindee)->function_bindings());
8096 new_bindings =
8097 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8098 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8099 i = 0;
8100 for (int n = old_bindings->length(); i < n; i++) {
8101 new_bindings->set(i, old_bindings->get(i));
8102 }
8103 } else {
8104 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8105 new_bindings = isolate->factory()->NewFixedArray(array_size);
8106 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8107 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8108 i = 2;
8109 }
8110 // Copy arguments, skipping the first which is "this_arg".
8111 for (int j = 0; j < argc; j++, i++) {
8112 new_bindings->set(i, *arguments[j + 1]);
8113 }
8114 new_bindings->set_map(isolate->heap()->fixed_cow_array_map());
8115 bound_function->set_function_bindings(*new_bindings);
8116
8117 // Update length.
8118 Handle<String> length_symbol = isolate->factory()->length_symbol();
8119 Handle<Object> new_length(args.at<Object>(3));
8120 PropertyAttributes attr =
8121 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8122 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8123 return *bound_function;
8124}
8125
8126
8127RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8128 HandleScope handles(isolate);
8129 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008130 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008131 if (callable->IsJSFunction()) {
8132 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8133 if (function->shared()->bound()) {
8134 Handle<FixedArray> bindings(function->function_bindings());
8135 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8136 return *isolate->factory()->NewJSArrayWithElements(bindings);
8137 }
8138 }
8139 return isolate->heap()->undefined_value();
8140}
8141
8142
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008143RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008144 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008145 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008146 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008147 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008148 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008149
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008150 // The argument is a bound function. Extract its bound arguments
8151 // and callable.
8152 Handle<FixedArray> bound_args =
8153 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8154 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8155 Handle<Object> bound_function(
8156 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8157 ASSERT(!bound_function->IsJSFunction() ||
8158 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008159
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008160 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008161 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008162 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008163 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008164 param_data[i] = Handle<Object>(bound_args->get(
8165 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008166 }
8167
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008168 if (!bound_function->IsJSFunction()) {
8169 bool exception_thrown;
8170 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8171 &exception_thrown);
8172 if (exception_thrown) return Failure::Exception();
8173 }
8174 ASSERT(bound_function->IsJSFunction());
8175
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008176 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008177 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008178 Execution::New(Handle<JSFunction>::cast(bound_function),
8179 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008180 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008181 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008182 }
8183 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008184 return *result;
8185}
8186
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008187
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008188static void TrySettingInlineConstructStub(Isolate* isolate,
8189 Handle<JSFunction> function) {
8190 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008191 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008192 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008193 }
8194 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008195 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008196 Handle<Code> code = compiler.CompileConstructStub(function);
8197 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008198 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008199}
8200
8201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008202RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008203 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008204 ASSERT(args.length() == 1);
8205
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008206 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008207
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008208 // If the constructor isn't a proper function we throw a type error.
8209 if (!constructor->IsJSFunction()) {
8210 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8211 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008212 isolate->factory()->NewTypeError("not_constructor", arguments);
8213 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008214 }
8215
8216 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008217
8218 // If function should not have prototype, construction is not allowed. In this
8219 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008220 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008221 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8222 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008223 isolate->factory()->NewTypeError("not_constructor", arguments);
8224 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008225 }
8226
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008227#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008228 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008229 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008230 if (debug->StepInActive()) {
8231 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008232 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008233#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008234
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008235 if (function->has_initial_map()) {
8236 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008237 // The 'Function' function ignores the receiver object when
8238 // called using 'new' and creates a new JSFunction object that
8239 // is returned. The receiver object is only used for error
8240 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008241 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008242 // allocate JSFunctions since it does not properly initialize
8243 // the shared part of the function. Since the receiver is
8244 // ignored anyway, we use the global object as the receiver
8245 // instead of a new JSFunction object. This way, errors are
8246 // reported the same way whether or not 'Function' is called
8247 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008248 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008249 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250 }
8251
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008252 // The function should be compiled for the optimization hints to be
8253 // available. We cannot use EnsureCompiled because that forces a
8254 // compilation through the shared function info which makes it
8255 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008256 if (!function->is_compiled()) {
8257 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8258 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008259
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008260 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008261 if (!function->has_initial_map() &&
8262 shared->IsInobjectSlackTrackingInProgress()) {
8263 // The tracking is already in progress for another function. We can only
8264 // track one initial_map at a time, so we force the completion before the
8265 // function is called as a constructor for the first time.
8266 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008267 }
8268
8269 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008270 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8271 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008272 // Delay setting the stub if inobject slack tracking is in progress.
8273 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008274 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008275 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008276
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008277 isolate->counters()->constructed_objects()->Increment();
8278 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008279
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008280 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008281}
8282
8283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008284RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008285 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008286 ASSERT(args.length() == 1);
8287
8288 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8289 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008290 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008291
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008292 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008293}
8294
8295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008296RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008297 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008298 ASSERT(args.length() == 1);
8299
8300 Handle<JSFunction> function = args.at<JSFunction>(0);
8301#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008302 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008303 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008304 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008305 PrintF("]\n");
8306 }
8307#endif
8308
lrn@chromium.org34e60782011-09-15 07:25:40 +00008309 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008310 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008311 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008312 return Failure::Exception();
8313 }
8314
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008315 // All done. Return the compiled code.
8316 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008317 return function->code();
8318}
8319
8320
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008321RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008322 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008323 ASSERT(args.length() == 1);
8324 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008325
8326 // If the function is not compiled ignore the lazy
8327 // recompilation. This can happen if the debugger is activated and
8328 // the function is returned to the not compiled state.
8329 if (!function->shared()->is_compiled()) {
8330 function->ReplaceCode(function->shared()->code());
8331 return function->code();
8332 }
8333
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008334 // If the function is not optimizable or debugger is active continue using the
8335 // code from the full compiler.
8336 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008337 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008338 if (FLAG_trace_opt) {
8339 PrintF("[failed to optimize ");
8340 function->PrintName();
8341 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8342 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008343 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008344 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008345 function->ReplaceCode(function->shared()->code());
8346 return function->code();
8347 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008348 if (JSFunction::CompileOptimized(function,
8349 AstNode::kNoNumber,
8350 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008351 return function->code();
8352 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008353 if (FLAG_trace_opt) {
8354 PrintF("[failed to optimize ");
8355 function->PrintName();
8356 PrintF(": optimized compilation failed]\n");
8357 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008358 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008359 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008360}
8361
8362
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008363class ActivationsFinder : public ThreadVisitor {
8364 public:
8365 explicit ActivationsFinder(JSFunction* function)
8366 : function_(function), has_activations_(false) {}
8367
8368 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8369 if (has_activations_) return;
8370
8371 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8372 JavaScriptFrame* frame = it.frame();
8373 if (frame->is_optimized() && frame->function() == function_) {
8374 has_activations_ = true;
8375 return;
8376 }
8377 }
8378 }
8379
8380 bool has_activations() { return has_activations_; }
8381
8382 private:
8383 JSFunction* function_;
8384 bool has_activations_;
8385};
8386
8387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008388RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008389 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008390 ASSERT(args.length() == 1);
8391 RUNTIME_ASSERT(args[0]->IsSmi());
8392 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008393 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008394 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8395 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008396 int frames = deoptimizer->output_count();
8397
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008398 deoptimizer->MaterializeHeapNumbers();
8399 delete deoptimizer;
8400
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008401 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008402 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008403 for (int i = 0; i < frames - 1; i++) it.Advance();
8404 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008405
8406 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008407 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008408 Handle<Object> arguments;
8409 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008410 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008411 if (arguments.is_null()) {
8412 // FunctionGetArguments can't throw an exception, so cast away the
8413 // doubt with an assert.
8414 arguments = Handle<Object>(
8415 Accessors::FunctionGetArguments(*function,
8416 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008417 ASSERT(*arguments != isolate->heap()->null_value());
8418 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008419 }
8420 frame->SetExpression(i, *arguments);
8421 }
8422 }
8423
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008424 if (type == Deoptimizer::EAGER) {
8425 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008426 }
8427
8428 // Avoid doing too much work when running with --always-opt and keep
8429 // the optimized code around.
8430 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008431 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008432 }
8433
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008434 // Find other optimized activations of the function.
8435 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008436 while (!it.done()) {
8437 JavaScriptFrame* frame = it.frame();
8438 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008439 has_other_activations = true;
8440 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008441 }
8442 it.Advance();
8443 }
8444
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008445 if (!has_other_activations) {
8446 ActivationsFinder activations_finder(*function);
8447 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8448 has_other_activations = activations_finder.has_activations();
8449 }
8450
8451 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008452 if (FLAG_trace_deopt) {
8453 PrintF("[removing optimized code for: ");
8454 function->PrintName();
8455 PrintF("]\n");
8456 }
8457 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008458 } else {
8459 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008460 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008461 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008462}
8463
8464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008465RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008466 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008467 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008468 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008469}
8470
8471
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008472RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008473 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008474 ASSERT(args.length() == 1);
8475 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008476 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008477
8478 Deoptimizer::DeoptimizeFunction(*function);
8479
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008480 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008481}
8482
8483
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008484RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8485#if defined(USE_SIMULATOR)
8486 return isolate->heap()->true_value();
8487#else
8488 return isolate->heap()->false_value();
8489#endif
8490}
8491
8492
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008493RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8494 HandleScope scope(isolate);
8495 ASSERT(args.length() == 1);
8496 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8497 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8498 function->MarkForLazyRecompilation();
8499 return isolate->heap()->undefined_value();
8500}
8501
8502
lrn@chromium.org1c092762011-05-09 09:42:16 +00008503RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8504 HandleScope scope(isolate);
8505 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008506 // The least significant bit (after untagging) indicates whether the
8507 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008508 if (!V8::UseCrankshaft()) {
8509 return Smi::FromInt(4); // 4 == "never".
8510 }
8511 if (FLAG_always_opt) {
8512 return Smi::FromInt(3); // 3 == "always".
8513 }
8514 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8515 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8516 : Smi::FromInt(2); // 2 == "no".
8517}
8518
8519
8520RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8521 HandleScope scope(isolate);
8522 ASSERT(args.length() == 1);
8523 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8524 return Smi::FromInt(function->shared()->opt_count());
8525}
8526
8527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008528RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008529 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008530 ASSERT(args.length() == 1);
8531 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8532
8533 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008534 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008535
8536 // We have hit a back edge in an unoptimized frame for a function that was
8537 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008538 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008539 // Keep track of whether we've succeeded in optimizing.
8540 bool succeeded = unoptimized->optimizable();
8541 if (succeeded) {
8542 // If we are trying to do OSR when there are already optimized
8543 // activations of the function, it means (a) the function is directly or
8544 // indirectly recursive and (b) an optimized invocation has been
8545 // deoptimized so that we are currently in an unoptimized activation.
8546 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008547 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008548 while (succeeded && !it.done()) {
8549 JavaScriptFrame* frame = it.frame();
8550 succeeded = !frame->is_optimized() || frame->function() != *function;
8551 it.Advance();
8552 }
8553 }
8554
8555 int ast_id = AstNode::kNoNumber;
8556 if (succeeded) {
8557 // The top JS function is this one, the PC is somewhere in the
8558 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008559 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008560 JavaScriptFrame* frame = it.frame();
8561 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008562 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008563 ASSERT(unoptimized->contains(frame->pc()));
8564
8565 // Use linear search of the unoptimized code's stack check table to find
8566 // the AST id matching the PC.
8567 Address start = unoptimized->instruction_start();
8568 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008569 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008570 uint32_t table_length = Memory::uint32_at(table_cursor);
8571 table_cursor += kIntSize;
8572 for (unsigned i = 0; i < table_length; ++i) {
8573 // Table entries are (AST id, pc offset) pairs.
8574 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8575 if (pc_offset == target_pc_offset) {
8576 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8577 break;
8578 }
8579 table_cursor += 2 * kIntSize;
8580 }
8581 ASSERT(ast_id != AstNode::kNoNumber);
8582 if (FLAG_trace_osr) {
8583 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8584 function->PrintName();
8585 PrintF("]\n");
8586 }
8587
8588 // Try to compile the optimized code. A true return value from
8589 // CompileOptimized means that compilation succeeded, not necessarily
8590 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008591 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008592 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008593 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8594 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008595 if (data->OsrPcOffset()->value() >= 0) {
8596 if (FLAG_trace_osr) {
8597 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008598 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008599 }
8600 ASSERT(data->OsrAstId()->value() == ast_id);
8601 } else {
8602 // We may never generate the desired OSR entry if we emit an
8603 // early deoptimize.
8604 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008605 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008606 } else {
8607 succeeded = false;
8608 }
8609 }
8610
8611 // Revert to the original stack checks in the original unoptimized code.
8612 if (FLAG_trace_osr) {
8613 PrintF("[restoring original stack checks in ");
8614 function->PrintName();
8615 PrintF("]\n");
8616 }
8617 StackCheckStub check_stub;
8618 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008619 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008620 Deoptimizer::RevertStackCheckCode(*unoptimized,
8621 *check_code,
8622 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008623
8624 // Allow OSR only at nesting level zero again.
8625 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8626
8627 // If the optimization attempt succeeded, return the AST id tagged as a
8628 // smi. This tells the builtin that we need to translate the unoptimized
8629 // frame to an optimized one.
8630 if (succeeded) {
8631 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8632 return Smi::FromInt(ast_id);
8633 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008634 if (function->IsMarkedForLazyRecompilation()) {
8635 function->ReplaceCode(function->shared()->code());
8636 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008637 return Smi::FromInt(-1);
8638 }
8639}
8640
8641
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008642RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8643 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8644 return isolate->heap()->undefined_value();
8645}
8646
8647
danno@chromium.orgc612e022011-11-10 11:38:15 +00008648RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8649 HandleScope scope(isolate);
8650 ASSERT(args.length() >= 2);
8651 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8652 Object* receiver = args[0];
8653 int argc = args.length() - 2;
8654
8655 // If there are too many arguments, allocate argv via malloc.
8656 const int argv_small_size = 10;
8657 Handle<Object> argv_small_buffer[argv_small_size];
8658 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8659 Handle<Object>* argv = argv_small_buffer;
8660 if (argc > argv_small_size) {
8661 argv = new Handle<Object>[argc];
8662 if (argv == NULL) return isolate->StackOverflow();
8663 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8664 }
8665
8666 for (int i = 0; i < argc; ++i) {
8667 MaybeObject* maybe = args[1 + i];
8668 Object* object;
8669 if (!maybe->To<Object>(&object)) return maybe;
8670 argv[i] = Handle<Object>(object);
8671 }
8672
8673 bool threw;
8674 Handle<JSReceiver> hfun(fun);
8675 Handle<Object> hreceiver(receiver);
8676 Handle<Object> result =
8677 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8678
8679 if (threw) return Failure::Exception();
8680 return *result;
8681}
8682
8683
lrn@chromium.org34e60782011-09-15 07:25:40 +00008684RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8685 HandleScope scope(isolate);
8686 ASSERT(args.length() == 5);
8687 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8688 Object* receiver = args[1];
8689 CONVERT_CHECKED(JSObject, arguments, args[2]);
8690 CONVERT_CHECKED(Smi, shift, args[3]);
8691 CONVERT_CHECKED(Smi, arity, args[4]);
8692
8693 int offset = shift->value();
8694 int argc = arity->value();
8695 ASSERT(offset >= 0);
8696 ASSERT(argc >= 0);
8697
8698 // If there are too many arguments, allocate argv via malloc.
8699 const int argv_small_size = 10;
8700 Handle<Object> argv_small_buffer[argv_small_size];
8701 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8702 Handle<Object>* argv = argv_small_buffer;
8703 if (argc > argv_small_size) {
8704 argv = new Handle<Object>[argc];
8705 if (argv == NULL) return isolate->StackOverflow();
8706 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8707 }
8708
8709 for (int i = 0; i < argc; ++i) {
8710 MaybeObject* maybe = arguments->GetElement(offset + i);
8711 Object* object;
8712 if (!maybe->To<Object>(&object)) return maybe;
8713 argv[i] = Handle<Object>(object);
8714 }
8715
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008716 bool threw;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008717 Handle<JSReceiver> hfun(fun);
8718 Handle<Object> hreceiver(receiver);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008719 Handle<Object> result =
8720 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008721
8722 if (threw) return Failure::Exception();
8723 return *result;
8724}
8725
8726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008727RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008728 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008729 ASSERT(args.length() == 1);
8730 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8731 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8732}
8733
8734
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008735RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008736 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008737 ASSERT(args.length() == 1);
8738 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8739 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8740}
8741
8742
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008743RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008744 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008745 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008746
kasper.lund7276f142008-07-30 08:49:36 +00008747 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008748 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008749 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008750 { MaybeObject* maybe_result =
8751 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008752 if (!maybe_result->ToObject(&result)) return maybe_result;
8753 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008754
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008755 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008756
kasper.lund7276f142008-07-30 08:49:36 +00008757 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008758}
8759
lrn@chromium.org303ada72010-10-27 09:33:13 +00008760
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008761RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8762 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008763 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008764 JSObject* extension_object;
8765 if (args[0]->IsJSObject()) {
8766 extension_object = JSObject::cast(args[0]);
8767 } else {
8768 // Convert the object to a proper JavaScript object.
8769 MaybeObject* maybe_js_object = args[0]->ToObject();
8770 if (!maybe_js_object->To(&extension_object)) {
8771 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8772 HandleScope scope(isolate);
8773 Handle<Object> handle = args.at<Object>(0);
8774 Handle<Object> result =
8775 isolate->factory()->NewTypeError("with_expression",
8776 HandleVector(&handle, 1));
8777 return isolate->Throw(*result);
8778 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008779 return maybe_js_object;
8780 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008781 }
8782 }
8783
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008784 JSFunction* function;
8785 if (args[1]->IsSmi()) {
8786 // A smi sentinel indicates a context nested inside global code rather
8787 // than some function. There is a canonical empty function that can be
8788 // gotten from the global context.
8789 function = isolate->context()->global_context()->closure();
8790 } else {
8791 function = JSFunction::cast(args[1]);
8792 }
8793
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008794 Context* context;
8795 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008796 isolate->heap()->AllocateWithContext(function,
8797 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008798 extension_object);
8799 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008800 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008801 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008802}
8803
8804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008805RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008806 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008807 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008808 String* name = String::cast(args[0]);
8809 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008810 JSFunction* function;
8811 if (args[2]->IsSmi()) {
8812 // A smi sentinel indicates a context nested inside global code rather
8813 // than some function. There is a canonical empty function that can be
8814 // gotten from the global context.
8815 function = isolate->context()->global_context()->closure();
8816 } else {
8817 function = JSFunction::cast(args[2]);
8818 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008819 Context* context;
8820 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008821 isolate->heap()->AllocateCatchContext(function,
8822 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008823 name,
8824 thrown_object);
8825 if (!maybe_context->To(&context)) return maybe_context;
8826 isolate->set_context(context);
8827 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008828}
8829
8830
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008831RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8832 NoHandleAllocation ha;
8833 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008834 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008835 JSFunction* function;
8836 if (args[1]->IsSmi()) {
8837 // A smi sentinel indicates a context nested inside global code rather
8838 // than some function. There is a canonical empty function that can be
8839 // gotten from the global context.
8840 function = isolate->context()->global_context()->closure();
8841 } else {
8842 function = JSFunction::cast(args[1]);
8843 }
8844 Context* context;
8845 MaybeObject* maybe_context =
8846 isolate->heap()->AllocateBlockContext(function,
8847 isolate->context(),
8848 scope_info);
8849 if (!maybe_context->To(&context)) return maybe_context;
8850 isolate->set_context(context);
8851 return context;
8852}
8853
8854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008855RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008856 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008857 ASSERT(args.length() == 2);
8858
8859 CONVERT_ARG_CHECKED(Context, context, 0);
8860 CONVERT_ARG_CHECKED(String, name, 1);
8861
8862 int index;
8863 PropertyAttributes attributes;
8864 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008865 BindingFlags binding_flags;
8866 Handle<Object> holder = context->Lookup(name,
8867 flags,
8868 &index,
8869 &attributes,
8870 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008872 // If the slot was not found the result is true.
8873 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008874 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008875 }
8876
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008877 // If the slot was found in a context, it should be DONT_DELETE.
8878 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008879 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008880 }
8881
8882 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008883 // the global object, or the subject of a with. Try to delete it
8884 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008885 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008886 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008887}
8888
8889
ager@chromium.orga1645e22009-09-09 19:27:10 +00008890// A mechanism to return a pair of Object pointers in registers (if possible).
8891// How this is achieved is calling convention-dependent.
8892// All currently supported x86 compiles uses calling conventions that are cdecl
8893// variants where a 64-bit value is returned in two 32-bit registers
8894// (edx:eax on ia32, r1:r0 on ARM).
8895// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8896// In Win64 calling convention, a struct of two pointers is returned in memory,
8897// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008898#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008899struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008900 MaybeObject* x;
8901 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008902};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008903
lrn@chromium.org303ada72010-10-27 09:33:13 +00008904static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008905 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008906 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8907 // In Win64 they are assigned to a hidden first argument.
8908 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008909}
8910#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008911typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008912static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008913 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008914 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008915}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008916#endif
8917
8918
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008919static inline MaybeObject* Unhole(Heap* heap,
8920 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008921 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008922 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8923 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008924 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008925}
8926
8927
danno@chromium.org40cb8782011-05-25 07:58:50 +00008928static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8929 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008930 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008931 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008932 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008933 JSFunction* context_extension_function =
8934 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008935 // If the holder isn't a context extension object, we just return it
8936 // as the receiver. This allows arguments objects to be used as
8937 // receivers, but only if they are put in the context scope chain
8938 // explicitly via a with-statement.
8939 Object* constructor = holder->map()->constructor();
8940 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008941 // Fall back to using the global object as the implicit receiver if
8942 // the property turns out to be a local variable allocated in a
8943 // context extension object - introduced via eval. Implicit global
8944 // receivers are indicated with the hole value.
8945 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008946}
8947
8948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008949static ObjectPair LoadContextSlotHelper(Arguments args,
8950 Isolate* isolate,
8951 bool throw_error) {
8952 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008953 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008954
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008955 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008956 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008957 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008958 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008959 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008960
8961 int index;
8962 PropertyAttributes attributes;
8963 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008964 BindingFlags binding_flags;
8965 Handle<Object> holder = context->Lookup(name,
8966 flags,
8967 &index,
8968 &attributes,
8969 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008970
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008971 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008972 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008973 ASSERT(holder->IsContext());
8974 // If the "property" we were looking for is a local variable, the
8975 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008976 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008977 // Use the hole as the receiver to signal that the receiver is implicit
8978 // and that the global receiver should be used (as distinguished from an
8979 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008980 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008981 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008982 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008983 switch (binding_flags) {
8984 case MUTABLE_CHECK_INITIALIZED:
8985 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8986 if (value->IsTheHole()) {
8987 Handle<Object> reference_error =
8988 isolate->factory()->NewReferenceError("not_defined",
8989 HandleVector(&name, 1));
8990 return MakePair(isolate->Throw(*reference_error), NULL);
8991 }
8992 // FALLTHROUGH
8993 case MUTABLE_IS_INITIALIZED:
8994 case IMMUTABLE_IS_INITIALIZED:
8995 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8996 ASSERT(!value->IsTheHole());
8997 return MakePair(value, *receiver);
8998 case IMMUTABLE_CHECK_INITIALIZED:
8999 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9000 case MISSING_BINDING:
9001 UNREACHABLE();
9002 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009003 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009004 }
9005
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009006 // Otherwise, if the slot was found the holder is a context extension
9007 // object, subject of a with, or a global object. We read the named
9008 // property from it.
9009 if (!holder.is_null()) {
9010 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9011 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009012 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009013 Handle<Object> receiver_handle(object->IsGlobalObject()
9014 ? GlobalObject::cast(*object)->global_receiver()
9015 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009016
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009017 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009018 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009019 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009020 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009021 }
9022
9023 if (throw_error) {
9024 // The property doesn't exist - throw exception.
9025 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009026 isolate->factory()->NewReferenceError("not_defined",
9027 HandleVector(&name, 1));
9028 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009029 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009030 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009031 return MakePair(isolate->heap()->undefined_value(),
9032 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009033 }
9034}
9035
9036
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009037RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009038 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009039}
9040
9041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009042RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009043 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009044}
9045
9046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009047RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009048 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009049 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009051 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009052 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009053 CONVERT_ARG_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009054 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9055 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9056 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009057
9058 int index;
9059 PropertyAttributes attributes;
9060 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009061 BindingFlags binding_flags;
9062 Handle<Object> holder = context->Lookup(name,
9063 flags,
9064 &index,
9065 &attributes,
9066 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009067
9068 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009069 // The property was found in a context slot.
9070 Handle<Context> context = Handle<Context>::cast(holder);
9071 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9072 context->get(index)->IsTheHole()) {
9073 Handle<Object> error =
9074 isolate->factory()->NewReferenceError("not_defined",
9075 HandleVector(&name, 1));
9076 return isolate->Throw(*error);
9077 }
9078 // Ignore if read_only variable.
9079 if ((attributes & READ_ONLY) == 0) {
9080 // Context is a fixed array and set cannot fail.
9081 context->set(index, *value);
9082 } else if (strict_mode == kStrictMode) {
9083 // Setting read only property in strict mode.
9084 Handle<Object> error =
9085 isolate->factory()->NewTypeError("strict_cannot_assign",
9086 HandleVector(&name, 1));
9087 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009088 }
9089 return *value;
9090 }
9091
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009092 // Slow case: The property is not in a context slot. It is either in a
9093 // context extension object, a property of the subject of a with, or a
9094 // property of the global object.
9095 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009096
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009097 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009098 // The property exists on the holder.
9099 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009100 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009101 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009102 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009103
9104 if (strict_mode == kStrictMode) {
9105 // Throw in strict mode (assignment to undefined variable).
9106 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009107 isolate->factory()->NewReferenceError(
9108 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009109 return isolate->Throw(*error);
9110 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009111 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009112 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009113 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009114 }
9115
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009116 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009117 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009118 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009119 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009120 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009121 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009122 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009123 // Setting read only property in strict mode.
9124 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009125 isolate->factory()->NewTypeError(
9126 "strict_cannot_assign", HandleVector(&name, 1));
9127 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009128 }
9129 return *value;
9130}
9131
9132
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009133RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009134 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009135 ASSERT(args.length() == 1);
9136
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009137 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009138}
9139
9140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009141RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009142 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009143 ASSERT(args.length() == 1);
9144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009145 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009146}
9147
9148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009149RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009150 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009151 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009152}
9153
9154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009155RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009156 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009157 ASSERT(args.length() == 1);
9158
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009159 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009160 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009161 isolate->factory()->NewReferenceError("not_defined",
9162 HandleVector(&name, 1));
9163 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009164}
9165
9166
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009167RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009168 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009169
9170 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009171 if (isolate->stack_guard()->IsStackOverflow()) {
9172 NoHandleAllocation na;
9173 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009174 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009175
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009176 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009177}
9178
9179
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009180static int StackSize() {
9181 int n = 0;
9182 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9183 return n;
9184}
9185
9186
9187static void PrintTransition(Object* result) {
9188 // indentation
9189 { const int nmax = 80;
9190 int n = StackSize();
9191 if (n <= nmax)
9192 PrintF("%4d:%*s", n, n, "");
9193 else
9194 PrintF("%4d:%*s", n, nmax, "...");
9195 }
9196
9197 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009198 JavaScriptFrame::PrintTop(stdout, true, false);
9199 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009200 } else {
9201 // function result
9202 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009203 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009204 PrintF("\n");
9205 }
9206}
9207
9208
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009209RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
9210 ASSERT(args.length() == 5);
9211 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9212 CONVERT_SMI_ARG_CHECKED(from_kind, 1);
9213 CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
9214 CONVERT_SMI_ARG_CHECKED(to_kind, 3);
9215 CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
9216 NoHandleAllocation ha;
9217 PrintF("*");
9218 obj->PrintElementsTransition(stdout,
9219 static_cast<ElementsKind>(from_kind), *from_elements,
9220 static_cast<ElementsKind>(to_kind), *to_elements);
9221 return isolate->heap()->undefined_value();
9222}
9223
9224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009225RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009226 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009227 NoHandleAllocation ha;
9228 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009229 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009230}
9231
9232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009233RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234 NoHandleAllocation ha;
9235 PrintTransition(args[0]);
9236 return args[0]; // return TOS
9237}
9238
9239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009240RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009241 NoHandleAllocation ha;
9242 ASSERT(args.length() == 1);
9243
9244#ifdef DEBUG
9245 if (args[0]->IsString()) {
9246 // If we have a string, assume it's a code "marker"
9247 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009248 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009249 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009250 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9251 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252 } else {
9253 PrintF("DebugPrint: ");
9254 }
9255 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009256 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009257 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009258 HeapObject::cast(args[0])->map()->Print();
9259 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009260#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009261 // ShortPrint is available in release mode. Print is not.
9262 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009263#endif
9264 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009265 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009266
9267 return args[0]; // return TOS
9268}
9269
9270
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009271RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009272 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009273 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009274 isolate->PrintStack();
9275 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009276}
9277
9278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009279RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009280 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009281 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009282
9283 // According to ECMA-262, section 15.9.1, page 117, the precision of
9284 // the number in a Date object representing a particular instant in
9285 // time is milliseconds. Therefore, we floor the result of getting
9286 // the OS time.
9287 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009288 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009289}
9290
9291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009292RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009293 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009294 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009295
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009296 CONVERT_ARG_CHECKED(String, str, 0);
9297 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009299 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009300
9301 MaybeObject* maybe_result_array =
9302 output->EnsureCanContainNonSmiElements();
9303 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009304 RUNTIME_ASSERT(output->HasFastElements());
9305
9306 AssertNoAllocation no_allocation;
9307
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009308 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009309 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9310 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009311 String::FlatContent str_content = str->GetFlatContent();
9312 if (str_content.IsAscii()) {
9313 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009314 output_array,
9315 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009316 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009317 ASSERT(str_content.IsTwoByte());
9318 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009319 output_array,
9320 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009321 }
9322
9323 if (result) {
9324 return *output;
9325 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009326 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009327 }
9328}
9329
9330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009331RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332 NoHandleAllocation ha;
9333 ASSERT(args.length() == 1);
9334
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009335 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009336 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009337 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009338}
9339
9340
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009341RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009342 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009343 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009345 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009346}
9347
9348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009349RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009350 NoHandleAllocation ha;
9351 ASSERT(args.length() == 1);
9352
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009353 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009354 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009355}
9356
9357
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009358RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009359 ASSERT(args.length() == 1);
9360 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009361 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009362 return JSGlobalObject::cast(global)->global_receiver();
9363}
9364
9365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009366RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009367 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009368 ASSERT_EQ(1, args.length());
9369 CONVERT_ARG_CHECKED(String, source, 0);
9370
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009371 source = Handle<String>(source->TryFlattenGetString());
9372 // Optimized fast case where we only have ascii characters.
9373 Handle<Object> result;
9374 if (source->IsSeqAsciiString()) {
9375 result = JsonParser<true>::Parse(source);
9376 } else {
9377 result = JsonParser<false>::Parse(source);
9378 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009379 if (result.is_null()) {
9380 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009381 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009382 return Failure::Exception();
9383 }
9384 return *result;
9385}
9386
9387
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009388bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9389 Handle<Context> context) {
9390 if (context->allow_code_gen_from_strings()->IsFalse()) {
9391 // Check with callback if set.
9392 AllowCodeGenerationFromStringsCallback callback =
9393 isolate->allow_code_gen_callback();
9394 if (callback == NULL) {
9395 // No callback set and code generation disallowed.
9396 return false;
9397 } else {
9398 // Callback set. Let it decide if code generation is allowed.
9399 VMState state(isolate, EXTERNAL);
9400 return callback(v8::Utils::ToLocal(context));
9401 }
9402 }
9403 return true;
9404}
9405
9406
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009407RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009408 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009409 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009410 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009411
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009412 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009413 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009414
9415 // Check if global context allows code generation from
9416 // strings. Throw an exception if it doesn't.
9417 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9418 return isolate->Throw(*isolate->factory()->NewError(
9419 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9420 }
9421
9422 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009423 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009424 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009425 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009426 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009427 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9428 context,
9429 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009430 return *fun;
9431}
9432
9433
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009434static ObjectPair CompileGlobalEval(Isolate* isolate,
9435 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009436 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009437 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009438 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009439 Handle<Context> context = Handle<Context>(isolate->context());
9440 Handle<Context> global_context = Handle<Context>(context->global_context());
9441
9442 // Check if global context allows code generation from
9443 // strings. Throw an exception if it doesn't.
9444 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9445 isolate->Throw(*isolate->factory()->NewError(
9446 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9447 return MakePair(Failure::Exception(), NULL);
9448 }
9449
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009450 // Deal with a normal eval call with a string argument. Compile it
9451 // and return the compiled function bound in the local context.
9452 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9453 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009454 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009455 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009456 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009457 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009458 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009459 Handle<JSFunction> compiled =
9460 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009461 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009462 return MakePair(*compiled, *receiver);
9463}
9464
9465
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009466RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009467 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009468
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009469 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009470 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009471
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009472 // If "eval" didn't refer to the original GlobalEval, it's not a
9473 // direct call to eval.
9474 // (And even if it is, but the first argument isn't a string, just let
9475 // execution default to an indirect call to eval, which will also return
9476 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009477 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009478 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009479 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009480 }
9481
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009482 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009483 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009484 return CompileGlobalEval(isolate,
9485 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009486 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009487 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009488 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009489}
9490
9491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009492RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009493 // This utility adjusts the property attributes for newly created Function
9494 // object ("new Function(...)") by changing the map.
9495 // All it does is changing the prototype property to enumerable
9496 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009497 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009498 ASSERT(args.length() == 1);
9499 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009500
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009501 Handle<Map> map = func->shared()->is_classic_mode()
9502 ? isolate->function_instance_map()
9503 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009504
9505 ASSERT(func->map()->instance_type() == map->instance_type());
9506 ASSERT(func->map()->instance_size() == map->instance_size());
9507 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009508 return *func;
9509}
9510
9511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009512RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009513 // Allocate a block of memory in NewSpace (filled with a filler).
9514 // Use as fallback for allocation in generated code when NewSpace
9515 // is full.
9516 ASSERT(args.length() == 1);
9517 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9518 int size = size_smi->value();
9519 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9520 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009521 Heap* heap = isolate->heap();
9522 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009523 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009524 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009525 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009526 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009527 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009528 }
9529 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009530 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009531}
9532
9533
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009534// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009535// array. Returns true if the element was pushed on the stack and
9536// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009537RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009538 ASSERT(args.length() == 2);
9539 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009540 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009541 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009542 int length = Smi::cast(array->length())->value();
9543 FixedArray* elements = FixedArray::cast(array->elements());
9544 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009545 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009546 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009547 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009548 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009549 { MaybeObject* maybe_obj =
9550 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009551 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9552 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009553 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009554}
9555
9556
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009557/**
9558 * A simple visitor visits every element of Array's.
9559 * The backend storage can be a fixed array for fast elements case,
9560 * or a dictionary for sparse array. Since Dictionary is a subtype
9561 * of FixedArray, the class can be used by both fast and slow cases.
9562 * The second parameter of the constructor, fast_elements, specifies
9563 * whether the storage is a FixedArray or Dictionary.
9564 *
9565 * An index limit is used to deal with the situation that a result array
9566 * length overflows 32-bit non-negative integer.
9567 */
9568class ArrayConcatVisitor {
9569 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009570 ArrayConcatVisitor(Isolate* isolate,
9571 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009572 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009573 isolate_(isolate),
9574 storage_(Handle<FixedArray>::cast(
9575 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009576 index_offset_(0u),
9577 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009578
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009579 ~ArrayConcatVisitor() {
9580 clear_storage();
9581 }
9582
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009583 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009584 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009585 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009586
9587 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009588 if (index < static_cast<uint32_t>(storage_->length())) {
9589 storage_->set(index, *elm);
9590 return;
9591 }
9592 // Our initial estimate of length was foiled, possibly by
9593 // getters on the arrays increasing the length of later arrays
9594 // during iteration.
9595 // This shouldn't happen in anything but pathological cases.
9596 SetDictionaryMode(index);
9597 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009598 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009599 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009600 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009601 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009602 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009603 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009604 // Dictionary needed to grow.
9605 clear_storage();
9606 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009607 }
9608}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009609
9610 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009611 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9612 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009613 } else {
9614 index_offset_ += delta;
9615 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009616 }
9617
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009618 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009619 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009620 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009621 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009622 Handle<Map> map;
9623 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009624 map = isolate_->factory()->GetElementsTransitionMap(array,
9625 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009626 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009627 map = isolate_->factory()->GetElementsTransitionMap(array,
9628 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009629 }
9630 array->set_map(*map);
9631 array->set_length(*length);
9632 array->set_elements(*storage_);
9633 return array;
9634 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009635
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009636 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009637 // Convert storage to dictionary mode.
9638 void SetDictionaryMode(uint32_t index) {
9639 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009640 Handle<FixedArray> current_storage(*storage_);
9641 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009642 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009643 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9644 for (uint32_t i = 0; i < current_length; i++) {
9645 HandleScope loop_scope;
9646 Handle<Object> element(current_storage->get(i));
9647 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009648 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009649 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009650 if (!new_storage.is_identical_to(slow_storage)) {
9651 slow_storage = loop_scope.CloseAndEscape(new_storage);
9652 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009653 }
9654 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009655 clear_storage();
9656 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009657 fast_elements_ = false;
9658 }
9659
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009660 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009661 isolate_->global_handles()->Destroy(
9662 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009663 }
9664
9665 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009666 storage_ = Handle<FixedArray>::cast(
9667 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009668 }
9669
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009670 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009671 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009672 // Index after last seen index. Always less than or equal to
9673 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009674 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009675 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009676};
9677
9678
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009679static uint32_t EstimateElementCount(Handle<JSArray> array) {
9680 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9681 int element_count = 0;
9682 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009683 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009684 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009685 // Fast elements can't have lengths that are not representable by
9686 // a 32-bit signed integer.
9687 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9688 int fast_length = static_cast<int>(length);
9689 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9690 for (int i = 0; i < fast_length; i++) {
9691 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009692 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009693 break;
9694 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009695 case FAST_DOUBLE_ELEMENTS:
9696 // TODO(1810): Decide if it's worthwhile to implement this.
9697 UNREACHABLE();
9698 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009699 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009700 Handle<NumberDictionary> dictionary(
9701 NumberDictionary::cast(array->elements()));
9702 int capacity = dictionary->Capacity();
9703 for (int i = 0; i < capacity; i++) {
9704 Handle<Object> key(dictionary->KeyAt(i));
9705 if (dictionary->IsKey(*key)) {
9706 element_count++;
9707 }
9708 }
9709 break;
9710 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009711 case NON_STRICT_ARGUMENTS_ELEMENTS:
9712 case EXTERNAL_BYTE_ELEMENTS:
9713 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9714 case EXTERNAL_SHORT_ELEMENTS:
9715 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9716 case EXTERNAL_INT_ELEMENTS:
9717 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9718 case EXTERNAL_FLOAT_ELEMENTS:
9719 case EXTERNAL_DOUBLE_ELEMENTS:
9720 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009721 // External arrays are always dense.
9722 return length;
9723 }
9724 // As an estimate, we assume that the prototype doesn't contain any
9725 // inherited elements.
9726 return element_count;
9727}
9728
9729
9730
9731template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009732static void IterateExternalArrayElements(Isolate* isolate,
9733 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009734 bool elements_are_ints,
9735 bool elements_are_guaranteed_smis,
9736 ArrayConcatVisitor* visitor) {
9737 Handle<ExternalArrayClass> array(
9738 ExternalArrayClass::cast(receiver->elements()));
9739 uint32_t len = static_cast<uint32_t>(array->length());
9740
9741 ASSERT(visitor != NULL);
9742 if (elements_are_ints) {
9743 if (elements_are_guaranteed_smis) {
9744 for (uint32_t j = 0; j < len; j++) {
9745 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009746 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009747 visitor->visit(j, e);
9748 }
9749 } else {
9750 for (uint32_t j = 0; j < len; j++) {
9751 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009752 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009753 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9754 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9755 visitor->visit(j, e);
9756 } else {
9757 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009758 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009759 visitor->visit(j, e);
9760 }
9761 }
9762 }
9763 } else {
9764 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009765 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009766 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009767 visitor->visit(j, e);
9768 }
9769 }
9770}
9771
9772
9773// Used for sorting indices in a List<uint32_t>.
9774static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9775 uint32_t a = *ap;
9776 uint32_t b = *bp;
9777 return (a == b) ? 0 : (a < b) ? -1 : 1;
9778}
9779
9780
9781static void CollectElementIndices(Handle<JSObject> object,
9782 uint32_t range,
9783 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009784 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009785 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009786 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009787 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009788 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9789 uint32_t length = static_cast<uint32_t>(elements->length());
9790 if (range < length) length = range;
9791 for (uint32_t i = 0; i < length; i++) {
9792 if (!elements->get(i)->IsTheHole()) {
9793 indices->Add(i);
9794 }
9795 }
9796 break;
9797 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009798 case FAST_DOUBLE_ELEMENTS: {
9799 // TODO(1810): Decide if it's worthwhile to implement this.
9800 UNREACHABLE();
9801 break;
9802 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009803 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009804 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009805 uint32_t capacity = dict->Capacity();
9806 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009807 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009808 Handle<Object> k(dict->KeyAt(j));
9809 if (dict->IsKey(*k)) {
9810 ASSERT(k->IsNumber());
9811 uint32_t index = static_cast<uint32_t>(k->Number());
9812 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009813 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009814 }
9815 }
9816 }
9817 break;
9818 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009819 default: {
9820 int dense_elements_length;
9821 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009822 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009823 dense_elements_length =
9824 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009825 break;
9826 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009827 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009828 dense_elements_length =
9829 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009830 break;
9831 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009832 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009833 dense_elements_length =
9834 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009835 break;
9836 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009837 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009838 dense_elements_length =
9839 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009840 break;
9841 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009842 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009843 dense_elements_length =
9844 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009845 break;
9846 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009847 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009848 dense_elements_length =
9849 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009850 break;
9851 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009852 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009853 dense_elements_length =
9854 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009855 break;
9856 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009857 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009858 dense_elements_length =
9859 ExternalFloatArray::cast(object->elements())->length();
9860 break;
9861 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009862 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009863 dense_elements_length =
9864 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009865 break;
9866 }
9867 default:
9868 UNREACHABLE();
9869 dense_elements_length = 0;
9870 break;
9871 }
9872 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9873 if (range <= length) {
9874 length = range;
9875 // We will add all indices, so we might as well clear it first
9876 // and avoid duplicates.
9877 indices->Clear();
9878 }
9879 for (uint32_t i = 0; i < length; i++) {
9880 indices->Add(i);
9881 }
9882 if (length == range) return; // All indices accounted for already.
9883 break;
9884 }
9885 }
9886
9887 Handle<Object> prototype(object->GetPrototype());
9888 if (prototype->IsJSObject()) {
9889 // The prototype will usually have no inherited element indices,
9890 // but we have to check.
9891 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9892 }
9893}
9894
9895
9896/**
9897 * A helper function that visits elements of a JSArray in numerical
9898 * order.
9899 *
9900 * The visitor argument called for each existing element in the array
9901 * with the element index and the element's value.
9902 * Afterwards it increments the base-index of the visitor by the array
9903 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009904 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009905 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009906static bool IterateElements(Isolate* isolate,
9907 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009908 ArrayConcatVisitor* visitor) {
9909 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9910 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009911 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009912 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009913 // Run through the elements FixedArray and use HasElement and GetElement
9914 // to check the prototype for missing elements.
9915 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9916 int fast_length = static_cast<int>(length);
9917 ASSERT(fast_length <= elements->length());
9918 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009919 HandleScope loop_scope(isolate);
9920 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009921 if (!element_value->IsTheHole()) {
9922 visitor->visit(j, element_value);
9923 } else if (receiver->HasElement(j)) {
9924 // Call GetElement on receiver, not its prototype, or getters won't
9925 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009926 element_value = Object::GetElement(receiver, j);
9927 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009928 visitor->visit(j, element_value);
9929 }
9930 }
9931 break;
9932 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009933 case FAST_DOUBLE_ELEMENTS: {
9934 // TODO(1810): Decide if it's worthwhile to implement this.
9935 UNREACHABLE();
9936 break;
9937 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009938 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009939 Handle<NumberDictionary> dict(receiver->element_dictionary());
9940 List<uint32_t> indices(dict->Capacity() / 2);
9941 // Collect all indices in the object and the prototypes less
9942 // than length. This might introduce duplicates in the indices list.
9943 CollectElementIndices(receiver, length, &indices);
9944 indices.Sort(&compareUInt32);
9945 int j = 0;
9946 int n = indices.length();
9947 while (j < n) {
9948 HandleScope loop_scope;
9949 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009950 Handle<Object> element = Object::GetElement(receiver, index);
9951 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009952 visitor->visit(index, element);
9953 // Skip to next different index (i.e., omit duplicates).
9954 do {
9955 j++;
9956 } while (j < n && indices[j] == index);
9957 }
9958 break;
9959 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009960 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009961 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9962 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009963 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009964 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009965 visitor->visit(j, e);
9966 }
9967 break;
9968 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009969 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009970 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009971 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009972 break;
9973 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009974 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009975 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009976 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009977 break;
9978 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009979 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009980 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009981 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009982 break;
9983 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009984 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009985 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009986 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009987 break;
9988 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009989 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009990 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009991 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009992 break;
9993 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009994 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009995 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009996 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009997 break;
9998 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009999 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010000 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010001 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010002 break;
10003 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010004 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010005 IterateExternalArrayElements<ExternalDoubleArray, double>(
10006 isolate, receiver, false, false, visitor);
10007 break;
10008 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010009 default:
10010 UNREACHABLE();
10011 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010012 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010013 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010014 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010015}
10016
10017
10018/**
10019 * Array::concat implementation.
10020 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010021 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010022 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010023 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010024RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010025 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010026 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010027
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010028 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10029 int argument_count = static_cast<int>(arguments->length()->Number());
10030 RUNTIME_ASSERT(arguments->HasFastElements());
10031 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010032
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010033 // Pass 1: estimate the length and number of elements of the result.
10034 // The actual length can be larger if any of the arguments have getters
10035 // that mutate other arguments (but will otherwise be precise).
10036 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010037
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010038 uint32_t estimate_result_length = 0;
10039 uint32_t estimate_nof_elements = 0;
10040 {
10041 for (int i = 0; i < argument_count; i++) {
10042 HandleScope loop_scope;
10043 Handle<Object> obj(elements->get(i));
10044 uint32_t length_estimate;
10045 uint32_t element_estimate;
10046 if (obj->IsJSArray()) {
10047 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010048 // TODO(1810): Find out if it's worthwhile to properly support
10049 // arbitrary ElementsKinds. For now, pessimistically transition to
10050 // FAST_ELEMENTS.
10051 if (array->HasFastDoubleElements()) {
10052 array = Handle<JSArray>::cast(
10053 TransitionElementsKind(array, FAST_ELEMENTS));
10054 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010055 length_estimate =
10056 static_cast<uint32_t>(array->length()->Number());
10057 element_estimate =
10058 EstimateElementCount(array);
10059 } else {
10060 length_estimate = 1;
10061 element_estimate = 1;
10062 }
10063 // Avoid overflows by capping at kMaxElementCount.
10064 if (JSObject::kMaxElementCount - estimate_result_length <
10065 length_estimate) {
10066 estimate_result_length = JSObject::kMaxElementCount;
10067 } else {
10068 estimate_result_length += length_estimate;
10069 }
10070 if (JSObject::kMaxElementCount - estimate_nof_elements <
10071 element_estimate) {
10072 estimate_nof_elements = JSObject::kMaxElementCount;
10073 } else {
10074 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010075 }
10076 }
10077 }
10078
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010079 // If estimated number of elements is more than half of length, a
10080 // fixed array (fast case) is more time and space-efficient than a
10081 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010082 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010083
10084 Handle<FixedArray> storage;
10085 if (fast_case) {
10086 // The backing storage array must have non-existing elements to
10087 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010088 storage = isolate->factory()->NewFixedArrayWithHoles(
10089 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010090 } else {
10091 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10092 uint32_t at_least_space_for = estimate_nof_elements +
10093 (estimate_nof_elements >> 2);
10094 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010095 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010096 }
10097
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010098 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010099
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010100 for (int i = 0; i < argument_count; i++) {
10101 Handle<Object> obj(elements->get(i));
10102 if (obj->IsJSArray()) {
10103 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010104 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010105 return Failure::Exception();
10106 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010107 } else {
10108 visitor.visit(0, obj);
10109 visitor.increase_index_offset(1);
10110 }
10111 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010112
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010113 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010114}
10115
10116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010117// This will not allocate (flatten the string), but it may run
10118// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010119RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010120 NoHandleAllocation ha;
10121 ASSERT(args.length() == 1);
10122
10123 CONVERT_CHECKED(String, string, args[0]);
10124 StringInputBuffer buffer(string);
10125 while (buffer.has_more()) {
10126 uint16_t character = buffer.GetNext();
10127 PrintF("%c", character);
10128 }
10129 return string;
10130}
10131
ager@chromium.org5ec48922009-05-05 07:25:34 +000010132// Moves all own elements of an object, that are below a limit, to positions
10133// starting at zero. All undefined values are placed after non-undefined values,
10134// and are followed by non-existing element. Does not change the length
10135// property.
10136// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010137RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010138 ASSERT(args.length() == 2);
10139 CONVERT_CHECKED(JSObject, object, args[0]);
10140 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10141 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010142}
10143
10144
10145// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010146RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010147 ASSERT(args.length() == 2);
10148 CONVERT_CHECKED(JSArray, from, args[0]);
10149 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010150 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010151 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010152 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010153 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10154 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010155 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010156 } else if (new_elements->map() ==
10157 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010158 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010159 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010160 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010161 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010162 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010163 Object* new_map;
10164 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010165 to->set_map(Map::cast(new_map));
10166 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010167 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010168 Object* obj;
10169 { MaybeObject* maybe_obj = from->ResetElements();
10170 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10171 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010172 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010173 return to;
10174}
10175
10176
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010177// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010178RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010179 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010180 CONVERT_CHECKED(JSObject, object, args[0]);
10181 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010182 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010183 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010184 } else if (object->IsJSArray()) {
10185 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010186 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010187 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010188 }
10189}
10190
10191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010192RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010193 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010194
10195 ASSERT_EQ(3, args.length());
10196
ager@chromium.orgac091b72010-05-05 07:34:42 +000010197 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010198 Handle<Object> key1 = args.at<Object>(1);
10199 Handle<Object> key2 = args.at<Object>(2);
10200
10201 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010202 if (!key1->ToArrayIndex(&index1)
10203 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010204 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010205 }
10206
ager@chromium.orgac091b72010-05-05 07:34:42 +000010207 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010208 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010209 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010210 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010211 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010212
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010213 RETURN_IF_EMPTY_HANDLE(isolate,
10214 SetElement(jsobject, index1, tmp2, kStrictMode));
10215 RETURN_IF_EMPTY_HANDLE(isolate,
10216 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010217
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010218 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010219}
10220
10221
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010222// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010223// might have elements. Can either return keys (positive integers) or
10224// intervals (pair of a negative integer (-start-1) followed by a
10225// positive (length)) or undefined values.
10226// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010227RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010228 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010229 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010230 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010231 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010232 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010233 // Create an array and get all the keys into it, then remove all the
10234 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010235 bool threw = false;
10236 Handle<FixedArray> keys =
10237 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10238 if (threw) return Failure::Exception();
10239
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240 int keys_length = keys->length();
10241 for (int i = 0; i < keys_length; i++) {
10242 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010243 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010244 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 // Zap invalid keys.
10246 keys->set_undefined(i);
10247 }
10248 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010249 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010251 ASSERT(array->HasFastElements() ||
10252 array->HasFastSmiOnlyElements() ||
10253 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010254 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010255 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010256 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010257 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010258 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010259 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010260 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010261 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010262 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010263 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010264 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265 }
10266}
10267
10268
10269// DefineAccessor takes an optional final argument which is the
10270// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10271// to the way accessors are implemented, it is set for both the getter
10272// and setter on the first call to DefineAccessor and ignored on
10273// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010274RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010275 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10276 // Compute attributes.
10277 PropertyAttributes attributes = NONE;
10278 if (args.length() == 5) {
10279 CONVERT_CHECKED(Smi, attrs, args[4]);
10280 int value = attrs->value();
10281 // Only attribute bits should be set.
10282 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10283 attributes = static_cast<PropertyAttributes>(value);
10284 }
10285
10286 CONVERT_CHECKED(JSObject, obj, args[0]);
10287 CONVERT_CHECKED(String, name, args[1]);
10288 CONVERT_CHECKED(Smi, flag, args[2]);
10289 CONVERT_CHECKED(JSFunction, fun, args[3]);
10290 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10291}
10292
10293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010294RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010295 ASSERT(args.length() == 3);
10296 CONVERT_CHECKED(JSObject, obj, args[0]);
10297 CONVERT_CHECKED(String, name, args[1]);
10298 CONVERT_CHECKED(Smi, flag, args[2]);
10299 return obj->LookupAccessor(name, flag->value() == 0);
10300}
10301
10302
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010303#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010304RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010305 ASSERT(args.length() == 0);
10306 return Execution::DebugBreakHelper();
10307}
10308
10309
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010310// Helper functions for wrapping and unwrapping stack frame ids.
10311static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010312 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010313 return Smi::FromInt(id >> 2);
10314}
10315
10316
10317static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10318 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10319}
10320
10321
10322// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010323// args[0]: debug event listener function to set or null or undefined for
10324// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010326RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010327 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010328 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10329 args[0]->IsUndefined() ||
10330 args[0]->IsNull());
10331 Handle<Object> callback = args.at<Object>(0);
10332 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010333 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010335 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010336}
10337
10338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010339RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010340 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010341 isolate->stack_guard()->DebugBreak();
10342 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010343}
10344
10345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010346static MaybeObject* DebugLookupResultValue(Heap* heap,
10347 Object* receiver,
10348 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010349 LookupResult* result,
10350 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010351 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010352 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010353 case NORMAL:
10354 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010355 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010356 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010357 }
10358 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010359 case FIELD:
10360 value =
10361 JSObject::cast(
10362 result->holder())->FastPropertyAt(result->GetFieldIndex());
10363 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010364 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010365 }
10366 return value;
10367 case CONSTANT_FUNCTION:
10368 return result->GetConstantFunction();
10369 case CALLBACKS: {
10370 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010371 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010372 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10373 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010374 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010375 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010376 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010377 maybe_value = heap->isolate()->pending_exception();
10378 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010379 if (caught_exception != NULL) {
10380 *caught_exception = true;
10381 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010382 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010383 }
10384 return value;
10385 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010386 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010387 }
10388 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010389 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010390 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010391 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010392 case CONSTANT_TRANSITION:
10393 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010394 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010395 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010396 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010397 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010398 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010399 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010400 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010401}
10402
10403
ager@chromium.org32912102009-01-16 10:38:43 +000010404// Get debugger related details for an object property.
10405// args[0]: object holding property
10406// args[1]: name of the property
10407//
10408// The array returned contains the following information:
10409// 0: Property value
10410// 1: Property details
10411// 2: Property value is exception
10412// 3: Getter function if defined
10413// 4: Setter function if defined
10414// Items 2-4 are only filled if the property has either a getter or a setter
10415// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010416RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010417 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010418
10419 ASSERT(args.length() == 2);
10420
10421 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10422 CONVERT_ARG_CHECKED(String, name, 1);
10423
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010424 // Make sure to set the current context to the context before the debugger was
10425 // entered (if the debugger is entered). The reason for switching context here
10426 // is that for some property lookups (accessors and interceptors) callbacks
10427 // into the embedding application can occour, and the embedding application
10428 // could have the assumption that its own global context is the current
10429 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010430 SaveContext save(isolate);
10431 if (isolate->debug()->InDebugger()) {
10432 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010433 }
10434
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010435 // Skip the global proxy as it has no properties and always delegates to the
10436 // real global object.
10437 if (obj->IsJSGlobalProxy()) {
10438 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10439 }
10440
10441
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010442 // Check if the name is trivially convertible to an index and get the element
10443 // if so.
10444 uint32_t index;
10445 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010446 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010447 Object* element_or_char;
10448 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010449 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010450 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10451 return maybe_element_or_char;
10452 }
10453 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010454 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010455 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010456 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010457 }
10458
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010459 // Find the number of objects making up this.
10460 int length = LocalPrototypeChainLength(*obj);
10461
10462 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010463 Handle<JSObject> jsproto = obj;
10464 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010465 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010466 jsproto->LocalLookup(*name, &result);
10467 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010468 // LookupResult is not GC safe as it holds raw object pointers.
10469 // GC can happen later in this code so put the required fields into
10470 // local variables using handles when required for later use.
10471 PropertyType result_type = result.type();
10472 Handle<Object> result_callback_obj;
10473 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010474 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10475 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010476 }
10477 Smi* property_details = result.GetPropertyDetails().AsSmi();
10478 // DebugLookupResultValue can cause GC so details from LookupResult needs
10479 // to be copied to handles before this.
10480 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010481 Object* raw_value;
10482 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010483 DebugLookupResultValue(isolate->heap(), *obj, *name,
10484 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010485 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10486 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010487 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010488
10489 // If the callback object is a fixed array then it contains JavaScript
10490 // getter and/or setter.
10491 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10492 result_callback_obj->IsFixedArray();
10493 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010494 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010495 details->set(0, *value);
10496 details->set(1, property_details);
10497 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010498 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010499 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10500 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10501 }
10502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010503 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010504 }
10505 if (i < length - 1) {
10506 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10507 }
10508 }
10509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010510 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010511}
10512
10513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010514RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010515 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010516
10517 ASSERT(args.length() == 2);
10518
10519 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10520 CONVERT_ARG_CHECKED(String, name, 1);
10521
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010522 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010523 obj->Lookup(*name, &result);
10524 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010525 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010526 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010527 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010528}
10529
10530
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010531// Return the property type calculated from the property details.
10532// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010533RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 ASSERT(args.length() == 1);
10535 CONVERT_CHECKED(Smi, details, args[0]);
10536 PropertyType type = PropertyDetails(details).type();
10537 return Smi::FromInt(static_cast<int>(type));
10538}
10539
10540
10541// Return the property attribute calculated from the property details.
10542// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010543RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010544 ASSERT(args.length() == 1);
10545 CONVERT_CHECKED(Smi, details, args[0]);
10546 PropertyAttributes attributes = PropertyDetails(details).attributes();
10547 return Smi::FromInt(static_cast<int>(attributes));
10548}
10549
10550
10551// Return the property insertion index calculated from the property details.
10552// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010553RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010554 ASSERT(args.length() == 1);
10555 CONVERT_CHECKED(Smi, details, args[0]);
10556 int index = PropertyDetails(details).index();
10557 return Smi::FromInt(index);
10558}
10559
10560
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561// Return property value from named interceptor.
10562// args[0]: object
10563// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010564RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010565 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010566 ASSERT(args.length() == 2);
10567 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10568 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10569 CONVERT_ARG_CHECKED(String, name, 1);
10570
10571 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010572 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010573}
10574
10575
10576// Return element value from indexed interceptor.
10577// args[0]: object
10578// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010579RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010580 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010581 ASSERT(args.length() == 2);
10582 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10583 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10584 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10585
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010586 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587}
10588
10589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010590RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010591 ASSERT(args.length() >= 1);
10592 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010593 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010594 if (isolate->debug()->break_id() == 0 ||
10595 break_id != isolate->debug()->break_id()) {
10596 return isolate->Throw(
10597 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010598 }
10599
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010600 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010601}
10602
10603
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010604RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010605 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010606 ASSERT(args.length() == 1);
10607
10608 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010609 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010610 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10611 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010612 if (!maybe_result->ToObject(&result)) return maybe_result;
10613 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010614
10615 // Count all frames which are relevant to debugging stack trace.
10616 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010617 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010618 if (id == StackFrame::NO_ID) {
10619 // If there is no JavaScript stack frame count is 0.
10620 return Smi::FromInt(0);
10621 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010622
10623 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10624 n += it.frame()->GetInlineCount();
10625 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010626 return Smi::FromInt(n);
10627}
10628
10629
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010630class FrameInspector {
10631 public:
10632 FrameInspector(JavaScriptFrame* frame,
10633 int inlined_frame_index,
10634 Isolate* isolate)
10635 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10636 // Calculate the deoptimized frame.
10637 if (frame->is_optimized()) {
10638 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10639 frame, inlined_frame_index, isolate);
10640 }
10641 has_adapted_arguments_ = frame_->has_adapted_arguments();
10642 is_optimized_ = frame_->is_optimized();
10643 }
10644
10645 ~FrameInspector() {
10646 // Get rid of the calculated deoptimized frame if any.
10647 if (deoptimized_frame_ != NULL) {
10648 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10649 isolate_);
10650 }
10651 }
10652
10653 int GetParametersCount() {
10654 return is_optimized_
10655 ? deoptimized_frame_->parameters_count()
10656 : frame_->ComputeParametersCount();
10657 }
10658 int expression_count() { return deoptimized_frame_->expression_count(); }
10659 Object* GetFunction() {
10660 return is_optimized_
10661 ? deoptimized_frame_->GetFunction()
10662 : frame_->function();
10663 }
10664 Object* GetParameter(int index) {
10665 return is_optimized_
10666 ? deoptimized_frame_->GetParameter(index)
10667 : frame_->GetParameter(index);
10668 }
10669 Object* GetExpression(int index) {
10670 return is_optimized_
10671 ? deoptimized_frame_->GetExpression(index)
10672 : frame_->GetExpression(index);
10673 }
10674
10675 // To inspect all the provided arguments the frame might need to be
10676 // replaced with the arguments frame.
10677 void SetArgumentsFrame(JavaScriptFrame* frame) {
10678 ASSERT(has_adapted_arguments_);
10679 frame_ = frame;
10680 is_optimized_ = frame_->is_optimized();
10681 ASSERT(!is_optimized_);
10682 }
10683
10684 private:
10685 JavaScriptFrame* frame_;
10686 DeoptimizedFrameInfo* deoptimized_frame_;
10687 Isolate* isolate_;
10688 bool is_optimized_;
10689 bool has_adapted_arguments_;
10690
10691 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10692};
10693
10694
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010695static const int kFrameDetailsFrameIdIndex = 0;
10696static const int kFrameDetailsReceiverIndex = 1;
10697static const int kFrameDetailsFunctionIndex = 2;
10698static const int kFrameDetailsArgumentCountIndex = 3;
10699static const int kFrameDetailsLocalCountIndex = 4;
10700static const int kFrameDetailsSourcePositionIndex = 5;
10701static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010702static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010703static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010704static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010705
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010706
10707static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10708 JavaScriptFrame* frame) {
10709 SaveContext* save = isolate->save_context();
10710 while (save != NULL && !save->IsBelowFrame(frame)) {
10711 save = save->prev();
10712 }
10713 ASSERT(save != NULL);
10714 return save;
10715}
10716
10717
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010718// Return an array with frame details
10719// args[0]: number: break id
10720// args[1]: number: frame index
10721//
10722// The array returned contains the following information:
10723// 0: Frame id
10724// 1: Receiver
10725// 2: Function
10726// 3: Argument count
10727// 4: Local count
10728// 5: Source position
10729// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010730// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010731// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010732// Arguments name, value
10733// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010734// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010735RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010736 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010737 ASSERT(args.length() == 2);
10738
10739 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010740 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010741 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10742 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010743 if (!maybe_check->ToObject(&check)) return maybe_check;
10744 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010745 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010746 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010747
10748 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010749 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010750 if (id == StackFrame::NO_ID) {
10751 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010752 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010753 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010754
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010755 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010756
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010757 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010758 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010759 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010760 if (index < count + it.frame()->GetInlineCount()) break;
10761 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010763 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010764
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010765 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010766 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010767 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010768 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010769 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010770
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771 // Traverse the saved contexts chain to find the active context for the
10772 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010773 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010774
10775 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010776 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010777
10778 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010779 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010780 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010781
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010782 // Check for constructor frame. Inlined frames cannot be construct calls.
10783 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010784 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010785 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010786
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010787 // Get scope info and read from it for local variable information.
10788 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010789 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010790 Handle<ScopeInfo> scope_info(shared->scope_info());
10791 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010792
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010793 // Get the locals names and values into a temporary array.
10794 //
10795 // TODO(1240907): Hide compiler-introduced stack variables
10796 // (e.g. .result)? For users of the debugger, they will probably be
10797 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010798 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010799 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010800
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010801 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010802 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010803 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010804 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010805 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010806 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010807 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010808 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010809 // Get the context containing declarations.
10810 Handle<Context> context(
10811 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010812 for (; i < scope_info->LocalCount(); ++i) {
10813 Handle<String> name(scope_info->LocalName(i));
10814 VariableMode mode;
10815 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010816 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010817 locals->set(i * 2 + 1, context->get(
10818 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010819 }
10820 }
10821
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010822 // Check whether this frame is positioned at return. If not top
10823 // frame or if the frame is optimized it cannot be at a return.
10824 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010825 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010826 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010827 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010828
10829 // If positioned just before return find the value to be returned and add it
10830 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010831 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010832 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010833 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010834 Address internal_frame_sp = NULL;
10835 while (!it2.done()) {
10836 if (it2.frame()->is_internal()) {
10837 internal_frame_sp = it2.frame()->sp();
10838 } else {
10839 if (it2.frame()->is_java_script()) {
10840 if (it2.frame()->id() == it.frame()->id()) {
10841 // The internal frame just before the JavaScript frame contains the
10842 // value to return on top. A debug break at return will create an
10843 // internal frame to store the return value (eax/rax/r0) before
10844 // entering the debug break exit frame.
10845 if (internal_frame_sp != NULL) {
10846 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010847 Handle<Object>(Memory::Object_at(internal_frame_sp),
10848 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010849 break;
10850 }
10851 }
10852 }
10853
10854 // Indicate that the previous frame was not an internal frame.
10855 internal_frame_sp = NULL;
10856 }
10857 it2.Advance();
10858 }
10859 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010860
10861 // Now advance to the arguments adapter frame (if any). It contains all
10862 // the provided parameters whereas the function frame always have the number
10863 // of arguments matching the functions parameters. The rest of the
10864 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010865 if (it.frame()->has_adapted_arguments()) {
10866 it.AdvanceToArgumentsFrame();
10867 frame_inspector.SetArgumentsFrame(it.frame());
10868 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010869
10870 // Find the number of arguments to fill. At least fill the number of
10871 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010872 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010873 if (argument_count < frame_inspector.GetParametersCount()) {
10874 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010875 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010876#ifdef DEBUG
10877 if (it.frame()->is_optimized()) {
10878 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10879 }
10880#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010881
10882 // Calculate the size of the result.
10883 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010884 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010885 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010886 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010887
10888 // Add the frame id.
10889 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10890
10891 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010892 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010893
10894 // Add the arguments count.
10895 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10896
10897 // Add the locals count
10898 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010899 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010900
10901 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010902 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010903 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10904 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010905 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010906 }
10907
10908 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010909 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010910
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010911 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010912 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010913
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010914 // Add flags to indicate information on whether this frame is
10915 // bit 0: invoked in the debugger context.
10916 // bit 1: optimized frame.
10917 // bit 2: inlined in optimized frame
10918 int flags = 0;
10919 if (*save->context() == *isolate->debug()->debug_context()) {
10920 flags |= 1 << 0;
10921 }
10922 if (it.frame()->is_optimized()) {
10923 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010924 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010925 }
10926 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010927
10928 // Fill the dynamic part.
10929 int details_index = kFrameDetailsFirstDynamicIndex;
10930
10931 // Add arguments name and value.
10932 for (int i = 0; i < argument_count; i++) {
10933 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010934 if (i < scope_info->ParameterCount()) {
10935 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010936 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010937 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010938 }
10939
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010940 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010941 if (i < it.frame()->ComputeParametersCount()) {
10942 // Get the value from the stack.
10943 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010944 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010945 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010946 }
10947 }
10948
10949 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010950 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010951 details->set(details_index++, locals->get(i));
10952 }
10953
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010954 // Add the value being returned.
10955 if (at_return) {
10956 details->set(details_index++, *return_value);
10957 }
10958
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959 // Add the receiver (same as in function frame).
10960 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10961 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010963 if (!receiver->IsJSObject() &&
10964 shared->is_classic_mode() &&
10965 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010966 // If the receiver is not a JSObject and the function is not a
10967 // builtin or strict-mode we have hit an optimization where a
10968 // value object is not converted into a wrapped JS objects. To
10969 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010970 // by creating correct wrapper object based on the calling frame's
10971 // global context.
10972 it.Advance();
10973 Handle<Context> calling_frames_global_context(
10974 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010975 receiver =
10976 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010977 }
10978 details->set(kFrameDetailsReceiverIndex, *receiver);
10979
10980 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010981 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010982}
10983
10984
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010985// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010986static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010987 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010988 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010989 Handle<Context> context,
10990 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010991 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010992 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10993 VariableMode mode;
10994 InitializationFlag init_flag;
10995 int context_index = scope_info->ContextSlotIndex(
10996 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010997
whesse@chromium.org7b260152011-06-20 15:33:18 +000010998 RETURN_IF_EMPTY_HANDLE_VALUE(
10999 isolate,
11000 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011001 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011002 Handle<Object>(context->get(context_index), isolate),
11003 NONE,
11004 kNonStrictMode),
11005 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011006 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011007
11008 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011009}
11010
11011
11012// Create a plain JSObject which materializes the local scope for the specified
11013// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011014static Handle<JSObject> MaterializeLocalScope(
11015 Isolate* isolate,
11016 JavaScriptFrame* frame,
11017 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011018 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011019 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011020 Handle<ScopeInfo> scope_info(shared->scope_info());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011021 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011022
11023 // Allocate and initialize a JSObject with all the arguments, stack locals
11024 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011025 Handle<JSObject> local_scope =
11026 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011027
11028 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011029 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011030 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011031 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011032 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011033 Handle<String>(scope_info->ParameterName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011034 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011035 NONE,
11036 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011037 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011038 }
11039
11040 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011041 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011042 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011043 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011044 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011045 Handle<String>(scope_info->StackLocalName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011046 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011047 NONE,
11048 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011049 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011050 }
11051
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011052 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011053 // Third fill all context locals.
11054 Handle<Context> frame_context(Context::cast(frame->context()));
11055 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011056 if (!CopyContextLocalsToScopeObject(
11057 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011058 return Handle<JSObject>();
11059 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011060
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011061 // Finally copy any properties from the function context extension.
11062 // These will be variables introduced by eval.
11063 if (function_context->closure() == *function) {
11064 if (function_context->has_extension() &&
11065 !function_context->IsGlobalContext()) {
11066 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011067 bool threw = false;
11068 Handle<FixedArray> keys =
11069 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11070 if (threw) return Handle<JSObject>();
11071
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011072 for (int i = 0; i < keys->length(); i++) {
11073 // Names of variables introduced by eval are strings.
11074 ASSERT(keys->get(i)->IsString());
11075 Handle<String> key(String::cast(keys->get(i)));
11076 RETURN_IF_EMPTY_HANDLE_VALUE(
11077 isolate,
11078 SetProperty(local_scope,
11079 key,
11080 GetProperty(ext, key),
11081 NONE,
11082 kNonStrictMode),
11083 Handle<JSObject>());
11084 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011085 }
11086 }
11087 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011088
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011089 return local_scope;
11090}
11091
11092
11093// Create a plain JSObject which materializes the closure content for the
11094// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011095static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11096 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011097 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011098
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011099 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011100 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011101
11102 // Allocate and initialize a JSObject with all the content of theis function
11103 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011104 Handle<JSObject> closure_scope =
11105 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011106
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011107 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011108 if (!CopyContextLocalsToScopeObject(
11109 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011110 return Handle<JSObject>();
11111 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112
11113 // Finally copy any properties from the function context extension. This will
11114 // be variables introduced by eval.
11115 if (context->has_extension()) {
11116 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011117 bool threw = false;
11118 Handle<FixedArray> keys =
11119 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11120 if (threw) return Handle<JSObject>();
11121
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011122 for (int i = 0; i < keys->length(); i++) {
11123 // Names of variables introduced by eval are strings.
11124 ASSERT(keys->get(i)->IsString());
11125 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011126 RETURN_IF_EMPTY_HANDLE_VALUE(
11127 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011128 SetProperty(closure_scope,
11129 key,
11130 GetProperty(ext, key),
11131 NONE,
11132 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011133 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011134 }
11135 }
11136
11137 return closure_scope;
11138}
11139
11140
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011141// Create a plain JSObject which materializes the scope for the specified
11142// catch context.
11143static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11144 Handle<Context> context) {
11145 ASSERT(context->IsCatchContext());
11146 Handle<String> name(String::cast(context->extension()));
11147 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11148 Handle<JSObject> catch_scope =
11149 isolate->factory()->NewJSObject(isolate->object_function());
11150 RETURN_IF_EMPTY_HANDLE_VALUE(
11151 isolate,
11152 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11153 Handle<JSObject>());
11154 return catch_scope;
11155}
11156
11157
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011158// Create a plain JSObject which materializes the block scope for the specified
11159// block context.
11160static Handle<JSObject> MaterializeBlockScope(
11161 Isolate* isolate,
11162 Handle<Context> context) {
11163 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011164 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011165
11166 // Allocate and initialize a JSObject with all the arguments, stack locals
11167 // heap locals and extension properties of the debugged function.
11168 Handle<JSObject> block_scope =
11169 isolate->factory()->NewJSObject(isolate->object_function());
11170
11171 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011172 if (!CopyContextLocalsToScopeObject(
11173 isolate, scope_info, context, block_scope)) {
11174 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011175 }
11176
11177 return block_scope;
11178}
11179
11180
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011181// Iterate over the actual scopes visible from a stack frame. The iteration
11182// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011183// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011184// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011185class ScopeIterator {
11186 public:
11187 enum ScopeType {
11188 ScopeTypeGlobal = 0,
11189 ScopeTypeLocal,
11190 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011191 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011192 ScopeTypeCatch,
11193 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011194 };
11195
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011196 ScopeIterator(Isolate* isolate,
11197 JavaScriptFrame* frame,
11198 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011199 : isolate_(isolate),
11200 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011201 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011202 function_(JSFunction::cast(frame->function())),
11203 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011204 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011205
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011206 // Catch the case when the debugger stops in an internal function.
11207 Handle<SharedFunctionInfo> shared_info(function_->shared());
11208 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11209 if (shared_info->script() == isolate->heap()->undefined_value()) {
11210 while (context_->closure() == *function_) {
11211 context_ = Handle<Context>(context_->previous(), isolate_);
11212 }
11213 return;
11214 }
11215
11216 // Get the debug info (create it if it does not exist).
11217 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11218 // Return if ensuring debug info failed.
11219 return;
11220 }
11221 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11222
11223 // Find the break point where execution has stopped.
11224 BreakLocationIterator break_location_iterator(debug_info,
11225 ALL_BREAK_LOCATIONS);
11226 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11227 if (break_location_iterator.IsExit()) {
11228 // We are within the return sequence. At the momemt it is not possible to
11229 // get a source position which is consistent with the current scope chain.
11230 // Thus all nested with, catch and block contexts are skipped and we only
11231 // provide the function scope.
11232 if (scope_info->HasContext()) {
11233 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11234 } else {
11235 while (context_->closure() == *function_) {
11236 context_ = Handle<Context>(context_->previous(), isolate_);
11237 }
11238 }
11239 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11240 } else {
11241 // Reparse the code and analyze the scopes.
11242 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11243 Handle<Script> script(Script::cast(shared_info->script()));
11244 Scope* scope = NULL;
11245
11246 // Check whether we are in global, eval or function code.
11247 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11248 if (scope_info->Type() != FUNCTION_SCOPE) {
11249 // Global or eval code.
11250 CompilationInfo info(script);
11251 if (scope_info->Type() == GLOBAL_SCOPE) {
11252 info.MarkAsGlobal();
11253 } else {
11254 ASSERT(scope_info->Type() == EVAL_SCOPE);
11255 info.MarkAsEval();
11256 info.SetCallingContext(Handle<Context>(function_->context()));
11257 }
11258 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11259 scope = info.function()->scope();
11260 }
11261 } else {
11262 // Function code
11263 CompilationInfo info(shared_info);
11264 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11265 scope = info.function()->scope();
11266 }
11267 }
11268
11269 // Retrieve the scope chain for the current position.
11270 if (scope != NULL) {
11271 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11272 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11273 } else {
11274 // A failed reparse indicates that the preparser has diverged from the
11275 // parser or that the preparse data given to the initial parse has been
11276 // faulty. We fail in debug mode but in release mode we only provide the
11277 // information we get from the context chain but nothing about
11278 // completely stack allocated scopes or stack allocated locals.
11279 UNREACHABLE();
11280 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011281 }
11282 }
11283
11284 // More scopes?
11285 bool Done() { return context_.is_null(); }
11286
11287 // Move to the next scope.
11288 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011289 ScopeType scope_type = Type();
11290 if (scope_type == ScopeTypeGlobal) {
11291 // The global scope is always the last in the chain.
11292 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011293 context_ = Handle<Context>();
11294 return;
11295 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011296 if (nested_scope_chain_.is_empty()) {
11297 context_ = Handle<Context>(context_->previous(), isolate_);
11298 } else {
11299 if (nested_scope_chain_.last()->HasContext()) {
11300 ASSERT(context_->previous() != NULL);
11301 context_ = Handle<Context>(context_->previous(), isolate_);
11302 }
11303 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011304 }
11305 }
11306
11307 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011308 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011309 if (!nested_scope_chain_.is_empty()) {
11310 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11311 switch (scope_info->Type()) {
11312 case FUNCTION_SCOPE:
11313 ASSERT(context_->IsFunctionContext() ||
11314 !scope_info->HasContext());
11315 return ScopeTypeLocal;
11316 case GLOBAL_SCOPE:
11317 ASSERT(context_->IsGlobalContext());
11318 return ScopeTypeGlobal;
11319 case WITH_SCOPE:
11320 ASSERT(context_->IsWithContext());
11321 return ScopeTypeWith;
11322 case CATCH_SCOPE:
11323 ASSERT(context_->IsCatchContext());
11324 return ScopeTypeCatch;
11325 case BLOCK_SCOPE:
11326 ASSERT(!scope_info->HasContext() ||
11327 context_->IsBlockContext());
11328 return ScopeTypeBlock;
11329 case EVAL_SCOPE:
11330 UNREACHABLE();
11331 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011332 }
11333 if (context_->IsGlobalContext()) {
11334 ASSERT(context_->global()->IsGlobalObject());
11335 return ScopeTypeGlobal;
11336 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011337 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011338 return ScopeTypeClosure;
11339 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011340 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011341 return ScopeTypeCatch;
11342 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011343 if (context_->IsBlockContext()) {
11344 return ScopeTypeBlock;
11345 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011346 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011347 return ScopeTypeWith;
11348 }
11349
11350 // Return the JavaScript object with the content of the current scope.
11351 Handle<JSObject> ScopeObject() {
11352 switch (Type()) {
11353 case ScopeIterator::ScopeTypeGlobal:
11354 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011355 case ScopeIterator::ScopeTypeLocal:
11356 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011357 ASSERT(nested_scope_chain_.length() == 1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011358 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011359 case ScopeIterator::ScopeTypeWith:
11360 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011361 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11362 case ScopeIterator::ScopeTypeCatch:
11363 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011364 case ScopeIterator::ScopeTypeClosure:
11365 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011366 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011367 case ScopeIterator::ScopeTypeBlock:
11368 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011369 }
11370 UNREACHABLE();
11371 return Handle<JSObject>();
11372 }
11373
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011374 Handle<ScopeInfo> CurrentScopeInfo() {
11375 if (!nested_scope_chain_.is_empty()) {
11376 return nested_scope_chain_.last();
11377 } else if (context_->IsBlockContext()) {
11378 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11379 } else if (context_->IsFunctionContext()) {
11380 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11381 }
11382 return Handle<ScopeInfo>::null();
11383 }
11384
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011385 // Return the context for this scope. For the local context there might not
11386 // be an actual context.
11387 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011388 if (Type() == ScopeTypeGlobal ||
11389 nested_scope_chain_.is_empty()) {
11390 return context_;
11391 } else if (nested_scope_chain_.last()->HasContext()) {
11392 return context_;
11393 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011394 return Handle<Context>();
11395 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011396 }
11397
11398#ifdef DEBUG
11399 // Debug print of the content of the current scope.
11400 void DebugPrint() {
11401 switch (Type()) {
11402 case ScopeIterator::ScopeTypeGlobal:
11403 PrintF("Global:\n");
11404 CurrentContext()->Print();
11405 break;
11406
11407 case ScopeIterator::ScopeTypeLocal: {
11408 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011409 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011410 if (!CurrentContext().is_null()) {
11411 CurrentContext()->Print();
11412 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011413 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011414 if (extension->IsJSContextExtensionObject()) {
11415 extension->Print();
11416 }
11417 }
11418 }
11419 break;
11420 }
11421
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011422 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011423 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011424 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011425 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011426
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011427 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011428 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011429 CurrentContext()->extension()->Print();
11430 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011431 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011432
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011433 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011434 PrintF("Closure:\n");
11435 CurrentContext()->Print();
11436 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011437 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011438 if (extension->IsJSContextExtensionObject()) {
11439 extension->Print();
11440 }
11441 }
11442 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011443
11444 default:
11445 UNREACHABLE();
11446 }
11447 PrintF("\n");
11448 }
11449#endif
11450
11451 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011452 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011453 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011454 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011455 Handle<JSFunction> function_;
11456 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011457 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011458
11459 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11460};
11461
11462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011463RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011464 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011465 ASSERT(args.length() == 2);
11466
11467 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011468 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011469 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11470 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011471 if (!maybe_check->ToObject(&check)) return maybe_check;
11472 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011473 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11474
11475 // Get the frame where the debugging is performed.
11476 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011477 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011478 JavaScriptFrame* frame = it.frame();
11479
11480 // Count the visible scopes.
11481 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011482 for (ScopeIterator it(isolate, frame, 0);
11483 !it.Done();
11484 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011485 n++;
11486 }
11487
11488 return Smi::FromInt(n);
11489}
11490
11491
11492static const int kScopeDetailsTypeIndex = 0;
11493static const int kScopeDetailsObjectIndex = 1;
11494static const int kScopeDetailsSize = 2;
11495
11496// Return an array with scope details
11497// args[0]: number: break id
11498// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011499// args[2]: number: inlined frame index
11500// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011501//
11502// The array returned contains the following information:
11503// 0: Scope type
11504// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011505RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011506 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011507 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011508
11509 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011510 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011511 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11512 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011513 if (!maybe_check->ToObject(&check)) return maybe_check;
11514 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011515 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011516 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11517 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011518
11519 // Get the frame where the debugging is performed.
11520 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011521 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011522 JavaScriptFrame* frame = frame_it.frame();
11523
11524 // Find the requested scope.
11525 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011526 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011527 for (; !it.Done() && n < index; it.Next()) {
11528 n++;
11529 }
11530 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011531 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011532 }
11533
11534 // Calculate the size of the result.
11535 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011536 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011537
11538 // Fill in scope details.
11539 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011540 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011541 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011542 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011543
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011544 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011545}
11546
11547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011548RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011549 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011550 ASSERT(args.length() == 0);
11551
11552#ifdef DEBUG
11553 // Print the scopes for the top frame.
11554 StackFrameLocator locator;
11555 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011556 for (ScopeIterator it(isolate, frame, 0);
11557 !it.Done();
11558 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011559 it.DebugPrint();
11560 }
11561#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011562 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011563}
11564
11565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011566RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011567 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011568 ASSERT(args.length() == 1);
11569
11570 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011571 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011572 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11573 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011574 if (!maybe_result->ToObject(&result)) return maybe_result;
11575 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011576
11577 // Count all archived V8 threads.
11578 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011579 for (ThreadState* thread =
11580 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011581 thread != NULL;
11582 thread = thread->Next()) {
11583 n++;
11584 }
11585
11586 // Total number of threads is current thread and archived threads.
11587 return Smi::FromInt(n + 1);
11588}
11589
11590
11591static const int kThreadDetailsCurrentThreadIndex = 0;
11592static const int kThreadDetailsThreadIdIndex = 1;
11593static const int kThreadDetailsSize = 2;
11594
11595// Return an array with thread details
11596// args[0]: number: break id
11597// args[1]: number: thread index
11598//
11599// The array returned contains the following information:
11600// 0: Is current thread?
11601// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011602RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011603 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011604 ASSERT(args.length() == 2);
11605
11606 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011607 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011608 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11609 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011610 if (!maybe_check->ToObject(&check)) return maybe_check;
11611 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011612 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11613
11614 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011615 Handle<FixedArray> details =
11616 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011617
11618 // Thread index 0 is current thread.
11619 if (index == 0) {
11620 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011621 details->set(kThreadDetailsCurrentThreadIndex,
11622 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011623 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011624 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011625 } else {
11626 // Find the thread with the requested index.
11627 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011628 ThreadState* thread =
11629 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011630 while (index != n && thread != NULL) {
11631 thread = thread->Next();
11632 n++;
11633 }
11634 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011635 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011636 }
11637
11638 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011639 details->set(kThreadDetailsCurrentThreadIndex,
11640 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011641 details->set(kThreadDetailsThreadIdIndex,
11642 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011643 }
11644
11645 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011647}
11648
11649
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011650// Sets the disable break state
11651// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011652RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011653 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011654 ASSERT(args.length() == 1);
11655 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011656 isolate->debug()->set_disable_break(disable_break);
11657 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011658}
11659
11660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011661RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011662 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011663 ASSERT(args.length() == 1);
11664
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011665 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11666 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011667 // Find the number of break points
11668 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011669 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011670 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011671 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011672 Handle<FixedArray>::cast(break_locations));
11673}
11674
11675
11676// Set a break point in a function
11677// args[0]: function
11678// args[1]: number: break source position (within the function source)
11679// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011680RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011681 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011682 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011683 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11684 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011685 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11686 RUNTIME_ASSERT(source_position >= 0);
11687 Handle<Object> break_point_object_arg = args.at<Object>(2);
11688
11689 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011690 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11691 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011692
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011693 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011694}
11695
11696
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011697Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11698 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011699 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011700 // Iterate the heap looking for SharedFunctionInfo generated from the
11701 // script. The inner most SharedFunctionInfo containing the source position
11702 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011703 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011704 // which is found is not compiled it is compiled and the heap is iterated
11705 // again as the compilation might create inner functions from the newly
11706 // compiled function and the actual requested break point might be in one of
11707 // these functions.
11708 bool done = false;
11709 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011710 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011711 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011712 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011713 { // Extra scope for iterator and no-allocation.
11714 isolate->heap()->EnsureHeapIsIterable();
11715 AssertNoAllocation no_alloc_during_heap_iteration;
11716 HeapIterator iterator;
11717 for (HeapObject* obj = iterator.next();
11718 obj != NULL; obj = iterator.next()) {
11719 if (obj->IsSharedFunctionInfo()) {
11720 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11721 if (shared->script() == *script) {
11722 // If the SharedFunctionInfo found has the requested script data and
11723 // contains the source position it is a candidate.
11724 int start_position = shared->function_token_position();
11725 if (start_position == RelocInfo::kNoPosition) {
11726 start_position = shared->start_position();
11727 }
11728 if (start_position <= position &&
11729 position <= shared->end_position()) {
11730 // If there is no candidate or this function is within the current
11731 // candidate this is the new candidate.
11732 if (target.is_null()) {
11733 target_start_position = start_position;
11734 target = shared;
11735 } else {
11736 if (target_start_position == start_position &&
11737 shared->end_position() == target->end_position()) {
11738 // If a top-level function contain only one function
11739 // declartion the source for the top-level and the
11740 // function is the same. In that case prefer the non
11741 // top-level function.
11742 if (!shared->is_toplevel()) {
11743 target_start_position = start_position;
11744 target = shared;
11745 }
11746 } else if (target_start_position <= start_position &&
11747 shared->end_position() <= target->end_position()) {
11748 // This containment check includes equality as a function
11749 // inside a top-level function can share either start or end
11750 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011751 target_start_position = start_position;
11752 target = shared;
11753 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011754 }
11755 }
11756 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011757 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011758 } // End for loop.
11759 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011760
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011761 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011762 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011763 }
11764
11765 // If the candidate found is compiled we are done. NOTE: when lazy
11766 // compilation of inner functions is introduced some additional checking
11767 // needs to be done here to compile inner functions.
11768 done = target->is_compiled();
11769 if (!done) {
11770 // If the candidate is not compiled compile it to reveal any inner
11771 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011772 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011773 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011774 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011775
11776 return *target;
11777}
11778
11779
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011780// Changes the state of a break point in a script and returns source position
11781// where break point was set. NOTE: Regarding performance see the NOTE for
11782// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011783// args[0]: script to set break point in
11784// args[1]: number: break source position (within the script source)
11785// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011786RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011787 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011788 ASSERT(args.length() == 3);
11789 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11790 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11791 RUNTIME_ASSERT(source_position >= 0);
11792 Handle<Object> break_point_object_arg = args.at<Object>(2);
11793
11794 // Get the script from the script wrapper.
11795 RUNTIME_ASSERT(wrapper->value()->IsScript());
11796 Handle<Script> script(Script::cast(wrapper->value()));
11797
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011798 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011799 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011800 if (!result->IsUndefined()) {
11801 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11802 // Find position within function. The script position might be before the
11803 // source position of the first function.
11804 int position;
11805 if (shared->start_position() > source_position) {
11806 position = 0;
11807 } else {
11808 position = source_position - shared->start_position();
11809 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011810 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011811 position += shared->start_position();
11812 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011813 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011814 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011815}
11816
11817
11818// Clear a break point
11819// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011820RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011821 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011822 ASSERT(args.length() == 1);
11823 Handle<Object> break_point_object_arg = args.at<Object>(0);
11824
11825 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011826 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011827
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011828 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011829}
11830
11831
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011832// Change the state of break on exceptions.
11833// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11834// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011835RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011836 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011837 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011838 RUNTIME_ASSERT(args[0]->IsNumber());
11839 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011840
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011841 // If the number doesn't match an enum value, the ChangeBreakOnException
11842 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011843 ExceptionBreakType type =
11844 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011845 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011846 isolate->debug()->ChangeBreakOnException(type, enable);
11847 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011848}
11849
11850
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011851// Returns the state of break on exceptions
11852// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011853RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011854 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011855 ASSERT(args.length() == 1);
11856 RUNTIME_ASSERT(args[0]->IsNumber());
11857
11858 ExceptionBreakType type =
11859 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011860 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011861 return Smi::FromInt(result);
11862}
11863
11864
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011865// Prepare for stepping
11866// args[0]: break id for checking execution state
11867// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011868// args[2]: number of times to perform the step, for step out it is the number
11869// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011870RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011871 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011872 ASSERT(args.length() == 3);
11873 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011874 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011875 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11876 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011877 if (!maybe_check->ToObject(&check)) return maybe_check;
11878 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011879 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011880 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011881 }
11882
11883 // Get the step action and check validity.
11884 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11885 if (step_action != StepIn &&
11886 step_action != StepNext &&
11887 step_action != StepOut &&
11888 step_action != StepInMin &&
11889 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011890 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011891 }
11892
11893 // Get the number of steps.
11894 int step_count = NumberToInt32(args[2]);
11895 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011896 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011897 }
11898
ager@chromium.orga1645e22009-09-09 19:27:10 +000011899 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011900 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011901
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011902 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011903 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11904 step_count);
11905 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011906}
11907
11908
11909// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011910RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011911 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011912 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011913 isolate->debug()->ClearStepping();
11914 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011915}
11916
11917
11918// Creates a copy of the with context chain. The copy of the context chain is
11919// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011920static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11921 Handle<JSFunction> function,
11922 Handle<Context> base,
11923 JavaScriptFrame* frame,
11924 int inlined_frame_index) {
11925 HandleScope scope(isolate);
11926 List<Handle<ScopeInfo> > scope_chain;
11927 List<Handle<Context> > context_chain;
11928
11929 ScopeIterator it(isolate, frame, inlined_frame_index);
11930 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11931 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11932 ASSERT(!it.Done());
11933 scope_chain.Add(it.CurrentScopeInfo());
11934 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011935 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011936
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011937 // At the end of the chain. Return the base context to link to.
11938 Handle<Context> context = base;
11939
11940 // Iteratively copy and or materialize the nested contexts.
11941 while (!scope_chain.is_empty()) {
11942 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11943 Handle<Context> current = context_chain.RemoveLast();
11944 ASSERT(!(scope_info->HasContext() & current.is_null()));
11945
11946 if (scope_info->Type() == CATCH_SCOPE) {
11947 Handle<String> name(String::cast(current->extension()));
11948 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11949 context =
11950 isolate->factory()->NewCatchContext(function,
11951 context,
11952 name,
11953 thrown_object);
11954 } else if (scope_info->Type() == BLOCK_SCOPE) {
11955 // Materialize the contents of the block scope into a JSObject.
11956 Handle<JSObject> block_scope_object =
11957 MaterializeBlockScope(isolate, current);
11958 if (block_scope_object.is_null()) {
11959 return Handle<Context>::null();
11960 }
11961 // Allocate a new function context for the debug evaluation and set the
11962 // extension object.
11963 Handle<Context> new_context =
11964 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11965 function);
11966 new_context->set_extension(*block_scope_object);
11967 new_context->set_previous(*context);
11968 context = new_context;
11969 } else {
11970 ASSERT(scope_info->Type() == WITH_SCOPE);
11971 ASSERT(current->IsWithContext());
11972 Handle<JSObject> extension(JSObject::cast(current->extension()));
11973 context =
11974 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011975 }
erikcorry0ad885c2011-11-21 13:51:57 +000011976 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011977
11978 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011979}
11980
11981
11982// Helper function to find or create the arguments object for
11983// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011984static Handle<Object> GetArgumentsObject(Isolate* isolate,
11985 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011986 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011987 Handle<JSFunction> function,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011988 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011989 Handle<Context> function_context) {
11990 // Try to find the value of 'arguments' to pass as parameter. If it is not
11991 // found (that is the debugged function does not reference 'arguments' and
11992 // does not support eval) then create an 'arguments' object.
11993 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011994 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011995 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011996 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011997 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011998 }
11999 }
12000
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012001 if (scope_info->HasHeapAllocatedLocals()) {
12002 VariableMode mode;
12003 InitializationFlag init_flag;
12004 index = scope_info->ContextSlotIndex(
12005 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012006 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012007 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012008 }
12009 }
12010
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012011 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
12012
12013 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012014 Handle<JSObject> arguments =
12015 isolate->factory()->NewArgumentsObject(function, length);
12016 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012017
12018 AssertNoAllocation no_gc;
12019 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012020 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012021 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012022 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012023 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012024 return arguments;
12025}
12026
12027
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012028static const char kSourceStr[] =
12029 "(function(arguments,__source__){return eval(__source__);})";
12030
12031
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012032// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012033// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012034// extension part has all the parameters and locals of the function on the
12035// stack frame. A function which calls eval with the code to evaluate is then
12036// compiled in this context and called in this context. As this context
12037// replaces the context of the function on the stack frame a new (empty)
12038// function is created as well to be used as the closure for the context.
12039// This function and the context acts as replacements for the function on the
12040// stack frame presenting the same view of the values of parameters and
12041// local variables as if the piece of JavaScript was evaluated at the point
12042// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012043RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012044 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012045
12046 // Check the execution state and decode arguments frame and source to be
12047 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012048 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012049 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012050 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12051 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012052 if (!maybe_check_result->ToObject(&check_result)) {
12053 return maybe_check_result;
12054 }
12055 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012056 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012057 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
12058 CONVERT_ARG_CHECKED(String, source, 3);
12059 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12060 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012061
12062 // Handle the processing of break.
12063 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012064
12065 // Get the frame where the debugging is performed.
12066 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012067 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012068 JavaScriptFrame* frame = it.frame();
12069 Handle<JSFunction> function(JSFunction::cast(frame->function()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012070 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012071
12072 // Traverse the saved contexts chain to find the active context for the
12073 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012074 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12075
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012076 SaveContext savex(isolate);
12077 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012078
12079 // Create the (empty) function replacing the function on the stack frame for
12080 // the purpose of evaluating in the context created below. It is important
12081 // that this function does not describe any parameters and local variables
12082 // in the context. If it does then this will cause problems with the lookup
12083 // in Context::Lookup, where context slots for parameters and local variables
12084 // are looked at before the extension object.
12085 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012086 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12087 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012088 go_between->set_context(function->context());
12089#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012090 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12091 ASSERT(go_between_scope_info->ParameterCount() == 0);
12092 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012093#endif
12094
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012095 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012096 Handle<JSObject> local_scope = MaterializeLocalScope(
12097 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012098 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012099
12100 // Allocate a new context for the debug evaluation and set the extension
12101 // object build.
12102 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012103 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12104 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012105 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012106 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012107 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012108 Handle<Context> function_context;
12109 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012110 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012111 function_context = Handle<Context>(frame_context->declaration_context());
12112 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012113 context = CopyNestedScopeContextChain(isolate,
12114 go_between,
12115 context,
12116 frame,
12117 inlined_frame_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012118
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012119 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012120 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012121 context =
12122 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012123 }
12124
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012125 // Wrap the evaluation statement in a new function compiled in the newly
12126 // created context. The function has one parameter which has to be called
12127 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012128 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012129 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012130
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012131 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012132 isolate->factory()->NewStringFromAscii(
12133 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012134
12135 // Currently, the eval code will be executed in non-strict mode,
12136 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012137 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012138 Compiler::CompileEval(function_source,
12139 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012140 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012141 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012142 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012143 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012144 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012145 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012146
12147 // Invoke the result of the compilation to get the evaluation function.
12148 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012149 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012150 Handle<Object> evaluation_function =
12151 Execution::Call(compiled_function, receiver, 0, NULL,
12152 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012153 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012154
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012155 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012156 frame,
12157 inlined_frame_index,
12158 function,
12159 scope_info,
12160 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012161
12162 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012163 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012164 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012165 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12166 receiver,
12167 ARRAY_SIZE(argv),
12168 argv,
12169 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012170 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012171
12172 // Skip the global proxy as it has no properties and always delegates to the
12173 // real global object.
12174 if (result->IsJSGlobalProxy()) {
12175 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12176 }
12177
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012178 return *result;
12179}
12180
12181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012182RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012183 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012184
12185 // Check the execution state and decode arguments frame and source to be
12186 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012187 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012188 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012189 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12190 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012191 if (!maybe_check_result->ToObject(&check_result)) {
12192 return maybe_check_result;
12193 }
12194 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012195 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012196 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012197 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012198
12199 // Handle the processing of break.
12200 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012201
12202 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012203 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012204 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012205 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012206 top = top->prev();
12207 }
12208 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012209 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012210 }
12211
12212 // Get the global context now set to the top context from before the
12213 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012214 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012215
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012216 bool is_global = true;
12217
12218 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012219 // Create a new with context with the additional context information between
12220 // the context of the debugged function and the eval code to be executed.
12221 context = isolate->factory()->NewWithContext(
12222 Handle<JSFunction>(context->closure()),
12223 context,
12224 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012225 is_global = false;
12226 }
12227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012228 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012229 // Currently, the eval code will be executed in non-strict mode,
12230 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012231 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012232 Compiler::CompileEval(source,
12233 context,
12234 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012235 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012236 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012237 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012238 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012239 Handle<JSFunction>(
12240 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12241 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012242
12243 // Invoke the result of the compilation to get the evaluation function.
12244 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012245 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012246 Handle<Object> result =
12247 Execution::Call(compiled_function, receiver, 0, NULL,
12248 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012249 // Clear the oneshot breakpoints so that the debugger does not step further.
12250 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012251 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012252 return *result;
12253}
12254
12255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012256RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012257 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012258 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012259
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012260 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012261 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012262
12263 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012264 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012265 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12266 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12267 // because using
12268 // instances->set(i, *GetScriptWrapper(script))
12269 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12270 // already have deferenced the instances handle.
12271 Handle<JSValue> wrapper = GetScriptWrapper(script);
12272 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012273 }
12274
12275 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012276 Handle<JSObject> result =
12277 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012278 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012279 return *result;
12280}
12281
12282
12283// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012284static int DebugReferencedBy(HeapIterator* iterator,
12285 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012286 Object* instance_filter, int max_references,
12287 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012288 JSFunction* arguments_function) {
12289 NoHandleAllocation ha;
12290 AssertNoAllocation no_alloc;
12291
12292 // Iterate the heap.
12293 int count = 0;
12294 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012295 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012296 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012297 (max_references == 0 || count < max_references)) {
12298 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012299 if (heap_obj->IsJSObject()) {
12300 // Skip context extension objects and argument arrays as these are
12301 // checked in the context of functions using them.
12302 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012303 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012304 obj->map()->constructor() == arguments_function) {
12305 continue;
12306 }
12307
12308 // Check if the JS object has a reference to the object looked for.
12309 if (obj->ReferencesObject(target)) {
12310 // Check instance filter if supplied. This is normally used to avoid
12311 // references from mirror objects (see Runtime_IsInPrototypeChain).
12312 if (!instance_filter->IsUndefined()) {
12313 Object* V = obj;
12314 while (true) {
12315 Object* prototype = V->GetPrototype();
12316 if (prototype->IsNull()) {
12317 break;
12318 }
12319 if (instance_filter == prototype) {
12320 obj = NULL; // Don't add this object.
12321 break;
12322 }
12323 V = prototype;
12324 }
12325 }
12326
12327 if (obj != NULL) {
12328 // Valid reference found add to instance array if supplied an update
12329 // count.
12330 if (instances != NULL && count < instances_size) {
12331 instances->set(count, obj);
12332 }
12333 last = obj;
12334 count++;
12335 }
12336 }
12337 }
12338 }
12339
12340 // Check for circular reference only. This can happen when the object is only
12341 // referenced from mirrors and has a circular reference in which case the
12342 // object is not really alive and would have been garbage collected if not
12343 // referenced from the mirror.
12344 if (count == 1 && last == target) {
12345 count = 0;
12346 }
12347
12348 // Return the number of referencing objects found.
12349 return count;
12350}
12351
12352
12353// Scan the heap for objects with direct references to an object
12354// args[0]: the object to find references to
12355// args[1]: constructor function for instances to exclude (Mirror)
12356// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012357RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012358 ASSERT(args.length() == 3);
12359
12360 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012361 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12362 // The heap iterator reserves the right to do a GC to make the heap iterable.
12363 // Due to the GC above we know it won't need to do that, but it seems cleaner
12364 // to get the heap iterator constructed before we start having unprotected
12365 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012366
12367 // Check parameters.
12368 CONVERT_CHECKED(JSObject, target, args[0]);
12369 Object* instance_filter = args[1];
12370 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12371 instance_filter->IsJSObject());
12372 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12373 RUNTIME_ASSERT(max_references >= 0);
12374
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012375
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012376 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012377 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012378 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012379 JSFunction* arguments_function =
12380 JSFunction::cast(arguments_boilerplate->map()->constructor());
12381
12382 // Get the number of referencing objects.
12383 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012384 HeapIterator heap_iterator;
12385 count = DebugReferencedBy(&heap_iterator,
12386 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012387 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012388
12389 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012390 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012391 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012392 if (!maybe_object->ToObject(&object)) return maybe_object;
12393 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012394 FixedArray* instances = FixedArray::cast(object);
12395
12396 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012397 // AllocateFixedArray above does not make the heap non-iterable.
12398 ASSERT(HEAP->IsHeapIterable());
12399 HeapIterator heap_iterator2;
12400 count = DebugReferencedBy(&heap_iterator2,
12401 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012402 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012403
12404 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012405 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012406 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012407 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012408 if (!maybe_result->ToObject(&result)) return maybe_result;
12409 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012410}
12411
12412
12413// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012414static int DebugConstructedBy(HeapIterator* iterator,
12415 JSFunction* constructor,
12416 int max_references,
12417 FixedArray* instances,
12418 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012419 AssertNoAllocation no_alloc;
12420
12421 // Iterate the heap.
12422 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012423 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012424 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012425 (max_references == 0 || count < max_references)) {
12426 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012427 if (heap_obj->IsJSObject()) {
12428 JSObject* obj = JSObject::cast(heap_obj);
12429 if (obj->map()->constructor() == constructor) {
12430 // Valid reference found add to instance array if supplied an update
12431 // count.
12432 if (instances != NULL && count < instances_size) {
12433 instances->set(count, obj);
12434 }
12435 count++;
12436 }
12437 }
12438 }
12439
12440 // Return the number of referencing objects found.
12441 return count;
12442}
12443
12444
12445// Scan the heap for objects constructed by a specific function.
12446// args[0]: the constructor to find instances of
12447// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012448RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012449 ASSERT(args.length() == 2);
12450
12451 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012452 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012453
12454 // Check parameters.
12455 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12456 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12457 RUNTIME_ASSERT(max_references >= 0);
12458
12459 // Get the number of referencing objects.
12460 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012461 HeapIterator heap_iterator;
12462 count = DebugConstructedBy(&heap_iterator,
12463 constructor,
12464 max_references,
12465 NULL,
12466 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012467
12468 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012469 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012470 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012471 if (!maybe_object->ToObject(&object)) return maybe_object;
12472 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012473 FixedArray* instances = FixedArray::cast(object);
12474
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012475 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012476 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012477 HeapIterator heap_iterator2;
12478 count = DebugConstructedBy(&heap_iterator2,
12479 constructor,
12480 max_references,
12481 instances,
12482 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012483
12484 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012485 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012486 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12487 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012488 if (!maybe_result->ToObject(&result)) return maybe_result;
12489 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012490 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012491}
12492
12493
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012494// Find the effective prototype object as returned by __proto__.
12495// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012496RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012497 ASSERT(args.length() == 1);
12498
12499 CONVERT_CHECKED(JSObject, obj, args[0]);
12500
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012501 // Use the __proto__ accessor.
12502 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012503}
12504
12505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012506RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012507 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012508 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012509 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012510}
12511
12512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012513RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012514#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012515 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012516 ASSERT(args.length() == 1);
12517 // Get the function and make sure it is compiled.
12518 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012519 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012520 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012521 return Failure::Exception();
12522 }
12523 func->code()->PrintLn();
12524#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012525 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012526}
ager@chromium.org9085a012009-05-11 19:22:57 +000012527
12528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012529RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012530#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012531 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012532 ASSERT(args.length() == 1);
12533 // Get the function and make sure it is compiled.
12534 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012535 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012536 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012537 return Failure::Exception();
12538 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012539 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012540#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012541 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012542}
12543
12544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012545RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012546 NoHandleAllocation ha;
12547 ASSERT(args.length() == 1);
12548
12549 CONVERT_CHECKED(JSFunction, f, args[0]);
12550 return f->shared()->inferred_name();
12551}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012552
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012553
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012554static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12555 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012556 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012557 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012558 int counter = 0;
12559 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012560 for (HeapObject* obj = iterator->next();
12561 obj != NULL;
12562 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012563 ASSERT(obj != NULL);
12564 if (!obj->IsSharedFunctionInfo()) {
12565 continue;
12566 }
12567 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12568 if (shared->script() != script) {
12569 continue;
12570 }
12571 if (counter < buffer_size) {
12572 buffer->set(counter, shared);
12573 }
12574 counter++;
12575 }
12576 return counter;
12577}
12578
12579// For a script finds all SharedFunctionInfo's in the heap that points
12580// to this script. Returns JSArray of SharedFunctionInfo wrapped
12581// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012582RUNTIME_FUNCTION(MaybeObject*,
12583 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012584 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012585 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012586 CONVERT_CHECKED(JSValue, script_value, args[0]);
12587
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012588
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012589 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12590
12591 const int kBufferSize = 32;
12592
12593 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012594 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012595 int number;
12596 {
12597 isolate->heap()->EnsureHeapIsIterable();
12598 AssertNoAllocation no_allocations;
12599 HeapIterator heap_iterator;
12600 Script* scr = *script;
12601 FixedArray* arr = *array;
12602 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12603 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012604 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012605 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012606 isolate->heap()->EnsureHeapIsIterable();
12607 AssertNoAllocation no_allocations;
12608 HeapIterator heap_iterator;
12609 Script* scr = *script;
12610 FixedArray* arr = *array;
12611 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012612 }
12613
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012614 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012615 result->set_length(Smi::FromInt(number));
12616
12617 LiveEdit::WrapSharedFunctionInfos(result);
12618
12619 return *result;
12620}
12621
12622// For a script calculates compilation information about all its functions.
12623// The script source is explicitly specified by the second argument.
12624// The source of the actual script is not used, however it is important that
12625// all generated code keeps references to this particular instance of script.
12626// Returns a JSArray of compilation infos. The array is ordered so that
12627// each function with all its descendant is always stored in a continues range
12628// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012629RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012630 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012631 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012632 CONVERT_CHECKED(JSValue, script, args[0]);
12633 CONVERT_ARG_CHECKED(String, source, 1);
12634 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12635
12636 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12637
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012638 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012639 return Failure::Exception();
12640 }
12641
12642 return result;
12643}
12644
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012645// Changes the source of the script to a new_source.
12646// If old_script_name is provided (i.e. is a String), also creates a copy of
12647// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012648RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012649 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012650 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012651 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12652 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012653 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012654
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012655 CONVERT_CHECKED(Script, original_script_pointer,
12656 original_script_value->value());
12657 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012658
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012659 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12660 new_source,
12661 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012662
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012663 if (old_script->IsScript()) {
12664 Handle<Script> script_handle(Script::cast(old_script));
12665 return *(GetScriptWrapper(script_handle));
12666 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012667 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012668 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012669}
12670
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012671
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012672RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012673 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012674 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012675 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12676 return LiveEdit::FunctionSourceUpdated(shared_info);
12677}
12678
12679
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012680// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012681RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012682 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012683 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012684 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12685 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12686
ager@chromium.orgac091b72010-05-05 07:34:42 +000012687 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012688}
12689
12690// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012691RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012692 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012693 HandleScope scope(isolate);
12694 Handle<Object> function_object(args[0], isolate);
12695 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012696
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012697 if (function_object->IsJSValue()) {
12698 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12699 if (script_object->IsJSValue()) {
12700 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012701 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012702 }
12703
12704 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12705 } else {
12706 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12707 // and we check it in this function.
12708 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012709
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012710 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012711}
12712
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012713
12714// In a code of a parent function replaces original function as embedded object
12715// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012716RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012717 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012718 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012719
12720 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12721 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12722 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12723
12724 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12725 subst_wrapper);
12726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012727 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012728}
12729
12730
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012731// Updates positions of a shared function info (first parameter) according
12732// to script source change. Text change is described in second parameter as
12733// array of groups of 3 numbers:
12734// (change_begin, change_end, change_end_new_position).
12735// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012736RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012737 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012738 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012739 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12740 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12741
ager@chromium.orgac091b72010-05-05 07:34:42 +000012742 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012743}
12744
12745
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012746// For array of SharedFunctionInfo's (each wrapped in JSValue)
12747// checks that none of them have activations on stacks (of any thread).
12748// Returns array of the same length with corresponding results of
12749// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012750RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012751 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012752 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012753 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012754 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012755
ager@chromium.org357bf652010-04-12 11:30:10 +000012756 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012757}
12758
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012759// Compares 2 strings line-by-line, then token-wise and returns diff in form
12760// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12761// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012762RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012763 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012764 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012765 CONVERT_ARG_CHECKED(String, s1, 0);
12766 CONVERT_ARG_CHECKED(String, s2, 1);
12767
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012768 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012769}
12770
12771
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012772// A testing entry. Returns statement position which is the closest to
12773// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012774RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012775 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012776 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012777 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12778 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12779
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012780 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012781
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012782 if (code->kind() != Code::FUNCTION &&
12783 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012784 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012785 }
12786
12787 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012788 int closest_pc = 0;
12789 int distance = kMaxInt;
12790 while (!it.done()) {
12791 int statement_position = static_cast<int>(it.rinfo()->data());
12792 // Check if this break point is closer that what was previously found.
12793 if (source_position <= statement_position &&
12794 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012795 closest_pc =
12796 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012797 distance = statement_position - source_position;
12798 // Check whether we can't get any closer.
12799 if (distance == 0) break;
12800 }
12801 it.next();
12802 }
12803
12804 return Smi::FromInt(closest_pc);
12805}
12806
12807
ager@chromium.org357bf652010-04-12 11:30:10 +000012808// Calls specified function with or without entering the debugger.
12809// This is used in unit tests to run code as if debugger is entered or simply
12810// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012811RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012812 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012813 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012814 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12815 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12816
12817 Handle<Object> result;
12818 bool pending_exception;
12819 {
12820 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012821 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012822 &pending_exception);
12823 } else {
12824 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012825 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012826 &pending_exception);
12827 }
12828 }
12829 if (!pending_exception) {
12830 return *result;
12831 } else {
12832 return Failure::Exception();
12833 }
12834}
12835
12836
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012837// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012838RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012839 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012840 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012841 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12842 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012843 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012844}
12845
12846
12847// Performs a GC.
12848// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012849RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012850 isolate->heap()->CollectAllGarbage(true);
12851 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012852}
12853
12854
12855// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012856RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012857 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012858 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012859 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012860 }
12861 return Smi::FromInt(usage);
12862}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012863
12864
12865// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012866RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012867#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012868 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012869#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012870 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012871#endif
12872}
12873
12874
12875// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012876RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012877#ifdef LIVE_OBJECT_LIST
12878 return LiveObjectList::Capture();
12879#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012880 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012881#endif
12882}
12883
12884
12885// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012886RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012887#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012888 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012889 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012890 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012891#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012892 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012893#endif
12894}
12895
12896
12897// Generates the response to a debugger request for a dump of the objects
12898// contained in the difference between the captured live object lists
12899// specified by id1 and id2.
12900// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12901// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012902RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012903#ifdef LIVE_OBJECT_LIST
12904 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012905 CONVERT_SMI_ARG_CHECKED(id1, 0);
12906 CONVERT_SMI_ARG_CHECKED(id2, 1);
12907 CONVERT_SMI_ARG_CHECKED(start, 2);
12908 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012909 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12910 EnterDebugger enter_debugger;
12911 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12912#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012913 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012914#endif
12915}
12916
12917
12918// Gets the specified object as requested by the debugger.
12919// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012920RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012921#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012922 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012923 Object* result = LiveObjectList::GetObj(obj_id);
12924 return result;
12925#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012926 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012927#endif
12928}
12929
12930
12931// Gets the obj id for the specified address if valid.
12932// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012933RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012934#ifdef LIVE_OBJECT_LIST
12935 HandleScope scope;
12936 CONVERT_ARG_CHECKED(String, address, 0);
12937 Object* result = LiveObjectList::GetObjId(address);
12938 return result;
12939#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012940 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012941#endif
12942}
12943
12944
12945// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012946RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012947#ifdef LIVE_OBJECT_LIST
12948 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012949 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012950 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12951 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12952 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12953 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12954 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12955
12956 Handle<JSObject> instance_filter;
12957 if (args[1]->IsJSObject()) {
12958 instance_filter = args.at<JSObject>(1);
12959 }
12960 bool verbose = false;
12961 if (args[2]->IsBoolean()) {
12962 verbose = args[2]->IsTrue();
12963 }
12964 int start = 0;
12965 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012966 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012967 }
12968 int limit = Smi::kMaxValue;
12969 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012970 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012971 }
12972
12973 return LiveObjectList::GetObjRetainers(obj_id,
12974 instance_filter,
12975 verbose,
12976 start,
12977 limit,
12978 filter_obj);
12979#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012980 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012981#endif
12982}
12983
12984
12985// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012986RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012987#ifdef LIVE_OBJECT_LIST
12988 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012989 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12990 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012991 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12992
12993 Handle<JSObject> instance_filter;
12994 if (args[2]->IsJSObject()) {
12995 instance_filter = args.at<JSObject>(2);
12996 }
12997
12998 Object* result =
12999 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13000 return result;
13001#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013002 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013003#endif
13004}
13005
13006
13007// Generates the response to a debugger request for a list of all
13008// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013009RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013010#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013011 CONVERT_SMI_ARG_CHECKED(start, 0);
13012 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013013 return LiveObjectList::Info(start, count);
13014#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013015 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013016#endif
13017}
13018
13019
13020// Gets a dump of the specified object as requested by the debugger.
13021// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013022RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013023#ifdef LIVE_OBJECT_LIST
13024 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013025 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013026 Object* result = LiveObjectList::PrintObj(obj_id);
13027 return result;
13028#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013029 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013030#endif
13031}
13032
13033
13034// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013035RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013036#ifdef LIVE_OBJECT_LIST
13037 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013038 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013039#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013040 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013041#endif
13042}
13043
13044
13045// Generates the response to a debugger request for a summary of the types
13046// of objects in the difference between the captured live object lists
13047// specified by id1 and id2.
13048// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13049// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013050RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013051#ifdef LIVE_OBJECT_LIST
13052 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013053 CONVERT_SMI_ARG_CHECKED(id1, 0);
13054 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013055 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13056
13057 EnterDebugger enter_debugger;
13058 return LiveObjectList::Summarize(id1, id2, filter_obj);
13059#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013060 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013061#endif
13062}
13063
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013064#endif // ENABLE_DEBUGGER_SUPPORT
13065
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013067RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013068 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013069 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013070 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013071}
13072
13073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013074RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013075 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013076 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013077 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013078}
13079
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013080
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013081// Finds the script object from the script data. NOTE: This operation uses
13082// heap traversal to find the function generated for the source position
13083// for the requested break point. For lazily compiled functions several heap
13084// traversals might be required rendering this operation as a rather slow
13085// operation. However for setting break points which is normally done through
13086// some kind of user interaction the performance is not crucial.
13087static Handle<Object> Runtime_GetScriptFromScriptName(
13088 Handle<String> script_name) {
13089 // Scan the heap for Script objects to find the script with the requested
13090 // script data.
13091 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013092 script_name->GetHeap()->EnsureHeapIsIterable();
13093 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013094 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013095 HeapObject* obj = NULL;
13096 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013097 // If a script is found check if it has the script data requested.
13098 if (obj->IsScript()) {
13099 if (Script::cast(obj)->name()->IsString()) {
13100 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13101 script = Handle<Script>(Script::cast(obj));
13102 }
13103 }
13104 }
13105 }
13106
13107 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013108 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013109
13110 // Return the script found.
13111 return GetScriptWrapper(script);
13112}
13113
13114
13115// Get the script object from script data. NOTE: Regarding performance
13116// see the NOTE for GetScriptFromScriptData.
13117// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013118RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013119 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013120
13121 ASSERT(args.length() == 1);
13122
13123 CONVERT_CHECKED(String, script_name, args[0]);
13124
13125 // Find the requested script.
13126 Handle<Object> result =
13127 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13128 return *result;
13129}
13130
13131
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013132// Determines whether the given stack frame should be displayed in
13133// a stack trace. The caller is the error constructor that asked
13134// for the stack trace to be collected. The first time a construct
13135// call to this function is encountered it is skipped. The seen_caller
13136// in/out parameter is used to remember if the caller has been seen
13137// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013138static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13139 Object* caller,
13140 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013141 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013142 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013143 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013144 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013145 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13146 Object* raw_fun = frame->function();
13147 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013148 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013149 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013150 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013151 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013152 *seen_caller = true;
13153 return false;
13154 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013155 // Skip all frames until we've seen the caller.
13156 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013157 // Also, skip non-visible built-in functions and any call with the builtins
13158 // object as receiver, so as to not reveal either the builtins object or
13159 // an internal function.
13160 // The --builtins-in-stack-traces command line flag allows including
13161 // internal call sites in the stack trace for debugging purposes.
13162 if (!FLAG_builtins_in_stack_traces) {
13163 JSFunction* fun = JSFunction::cast(raw_fun);
13164 if (frame->receiver()->IsJSBuiltinsObject() ||
13165 (fun->IsBuiltin() && !fun->shared()->native())) {
13166 return false;
13167 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013168 }
13169 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013170}
13171
13172
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013173// Collect the raw data for a stack trace. Returns an array of 4
13174// element segments each containing a receiver, function, code and
13175// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013176RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013177 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013178 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013179 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13180
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013181 HandleScope scope(isolate);
13182 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013183
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013184 limit = Max(limit, 0); // Ensure that limit is not negative.
13185 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013186 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013187 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013188
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013189 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013190 // If the caller parameter is a function we skip frames until we're
13191 // under it before starting to collect.
13192 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013193 int cursor = 0;
13194 int frames_seen = 0;
13195 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013196 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013197 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013198 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013199 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013200 // Set initial size to the maximum inlining level + 1 for the outermost
13201 // function.
13202 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013203 frame->Summarize(&frames);
13204 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013205 if (cursor + 4 > elements->length()) {
13206 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13207 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013208 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013209 for (int i = 0; i < cursor; i++) {
13210 new_elements->set(i, elements->get(i));
13211 }
13212 elements = new_elements;
13213 }
13214 ASSERT(cursor + 4 <= elements->length());
13215
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013216 Handle<Object> recv = frames[i].receiver();
13217 Handle<JSFunction> fun = frames[i].function();
13218 Handle<Code> code = frames[i].code();
13219 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013220 elements->set(cursor++, *recv);
13221 elements->set(cursor++, *fun);
13222 elements->set(cursor++, *code);
13223 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013224 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013225 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013226 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013227 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013228 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013229 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013230 return *result;
13231}
13232
13233
ager@chromium.org3811b432009-10-28 14:53:37 +000013234// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013235RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013236 ASSERT_EQ(args.length(), 0);
13237
13238 NoHandleAllocation ha;
13239
13240 const char* version_string = v8::V8::GetVersion();
13241
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013242 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13243 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013244}
13245
13246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013247RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013248 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013249 OS::PrintError("abort: %s\n",
13250 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013251 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013252 OS::Abort();
13253 UNREACHABLE();
13254 return NULL;
13255}
13256
13257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013258RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013259 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013260 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013261 Object* key = args[1];
13262
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013263 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013264 Object* o = cache->get(finger_index);
13265 if (o == key) {
13266 // The fastest case: hit the same place again.
13267 return cache->get(finger_index + 1);
13268 }
13269
13270 for (int i = finger_index - 2;
13271 i >= JSFunctionResultCache::kEntriesIndex;
13272 i -= 2) {
13273 o = cache->get(i);
13274 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013275 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013276 return cache->get(i + 1);
13277 }
13278 }
13279
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013280 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013281 ASSERT(size <= cache->length());
13282
13283 for (int i = size - 2; i > finger_index; i -= 2) {
13284 o = cache->get(i);
13285 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013286 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013287 return cache->get(i + 1);
13288 }
13289 }
13290
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013291 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013292 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013293
13294 Handle<JSFunctionResultCache> cache_handle(cache);
13295 Handle<Object> key_handle(key);
13296 Handle<Object> value;
13297 {
13298 Handle<JSFunction> factory(JSFunction::cast(
13299 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13300 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013301 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013302 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013303 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013304 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013305 value = Execution::Call(factory,
13306 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013307 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013308 argv,
13309 &pending_exception);
13310 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013311 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013312
13313#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013314 if (FLAG_verify_heap) {
13315 cache_handle->JSFunctionResultCacheVerify();
13316 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013317#endif
13318
13319 // Function invocation may have cleared the cache. Reread all the data.
13320 finger_index = cache_handle->finger_index();
13321 size = cache_handle->size();
13322
13323 // If we have spare room, put new data into it, otherwise evict post finger
13324 // entry which is likely to be the least recently used.
13325 int index = -1;
13326 if (size < cache_handle->length()) {
13327 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13328 index = size;
13329 } else {
13330 index = finger_index + JSFunctionResultCache::kEntrySize;
13331 if (index == cache_handle->length()) {
13332 index = JSFunctionResultCache::kEntriesIndex;
13333 }
13334 }
13335
13336 ASSERT(index % 2 == 0);
13337 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13338 ASSERT(index < cache_handle->length());
13339
13340 cache_handle->set(index, *key_handle);
13341 cache_handle->set(index + 1, *value);
13342 cache_handle->set_finger_index(index);
13343
13344#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013345 if (FLAG_verify_heap) {
13346 cache_handle->JSFunctionResultCacheVerify();
13347 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013348#endif
13349
13350 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013351}
13352
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013354RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013355 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013356 CONVERT_ARG_CHECKED(String, type, 0);
13357 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013358 return *isolate->factory()->NewJSMessageObject(
13359 type,
13360 arguments,
13361 0,
13362 0,
13363 isolate->factory()->undefined_value(),
13364 isolate->factory()->undefined_value(),
13365 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013366}
13367
13368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013369RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013370 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13371 return message->type();
13372}
13373
13374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013375RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013376 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13377 return message->arguments();
13378}
13379
13380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013381RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013382 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13383 return Smi::FromInt(message->start_position());
13384}
13385
13386
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013387RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013388 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13389 return message->script();
13390}
13391
13392
kasper.lund44510672008-07-25 07:37:58 +000013393#ifdef DEBUG
13394// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13395// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013396RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013397 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013398 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013399#define COUNT_ENTRY(Name, argc, ressize) + 1
13400 int entry_count = 0
13401 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13402 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13403 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13404#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013405 Factory* factory = isolate->factory();
13406 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013407 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013408 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013409#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013410 { \
13411 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013412 Handle<String> name; \
13413 /* Inline runtime functions have an underscore in front of the name. */ \
13414 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013415 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013416 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13417 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013418 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013419 Vector<const char>(#Name, StrLength(#Name))); \
13420 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013421 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013422 pair_elements->set(0, *name); \
13423 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013424 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013425 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013426 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013427 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013428 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013429 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013430 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013431 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013432#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013433 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013434 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013435 return *result;
13436}
kasper.lund44510672008-07-25 07:37:58 +000013437#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013438
13439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013440RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013441 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013442 CONVERT_CHECKED(String, format, args[0]);
13443 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013444 String::FlatContent format_content = format->GetFlatContent();
13445 RUNTIME_ASSERT(format_content.IsAscii());
13446 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013447 LOGGER->LogRuntime(chars, elms);
13448 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013449}
13450
13451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013452RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013453 UNREACHABLE(); // implemented as macro in the parser
13454 return NULL;
13455}
13456
13457
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013458#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13459 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13460 CONVERT_CHECKED(JSObject, obj, args[0]); \
13461 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13462 }
13463
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013464ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013465ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13466ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13467ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13468ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13469ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13470ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13471ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13472ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13473ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13474ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13475ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13476ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13477ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13478
13479#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13480
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013481
13482RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13483 ASSERT(args.length() == 2);
13484 CONVERT_CHECKED(JSObject, obj1, args[0]);
13485 CONVERT_CHECKED(JSObject, obj2, args[1]);
13486 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13487}
13488
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013489// ----------------------------------------------------------------------------
13490// Implementation of Runtime
13491
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013492#define F(name, number_of_args, result_size) \
13493 { Runtime::k##name, Runtime::RUNTIME, #name, \
13494 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013495
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013496
13497#define I(name, number_of_args, result_size) \
13498 { Runtime::kInline##name, Runtime::INLINE, \
13499 "_" #name, NULL, number_of_args, result_size },
13500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013501static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013502 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013503 INLINE_FUNCTION_LIST(I)
13504 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013505};
13506
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013508MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13509 Object* dictionary) {
13510 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013511 ASSERT(dictionary != NULL);
13512 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13513 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013514 Object* name_symbol;
13515 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013516 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013517 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13518 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013519 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013520 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13521 String::cast(name_symbol),
13522 Smi::FromInt(i),
13523 PropertyDetails(NONE, NORMAL));
13524 if (!maybe_dictionary->ToObject(&dictionary)) {
13525 // Non-recoverable failure. Calling code must restart heap
13526 // initialization.
13527 return maybe_dictionary;
13528 }
13529 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013530 }
13531 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013532}
13533
13534
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013535const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13536 Heap* heap = name->GetHeap();
13537 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013538 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013539 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013540 int function_index = Smi::cast(smi_index)->value();
13541 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013542 }
13543 return NULL;
13544}
13545
13546
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013547const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013548 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13549}
13550
13551
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013552void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013553 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013554 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013555 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013556 if (isolate->heap()->new_space()->AddFreshPage()) {
13557 return;
13558 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013559 // Try to do a garbage collection; ignore it if it fails. The C
13560 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013561 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013562 } else {
13563 // Handle last resort GC and make sure to allow future allocations
13564 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013565 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013566 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013567 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013568}
13569
13570
13571} } // namespace v8::internal